aboutsummaryrefslogtreecommitdiffstats
path: root/fs/overlayfs
diff options
context:
space:
mode:
authorMiklos Szeredi <mszeredi@redhat.com>2016-12-16 05:02:56 -0500
committerMiklos Szeredi <mszeredi@redhat.com>2016-12-16 05:02:56 -0500
commit8ee6059c58ea525f76b4efb98f8f66845f697efc (patch)
tree548cb4a104a2d00b0e8a01d7019e9c8c4c64f2cb /fs/overlayfs
parent3ee23ff1025a18796607cf4110a8ffa8e2d163fd (diff)
ovl: simplify lookup
If encountering a non-directory, then stop looking at lower layers. In this case the oe->opaque flag is not set anymore, which doesn't matter since existence of lower file is now checked at remove/rename time. Signed-off-by: Miklos Szeredi <mszeredi@redhat.com>
Diffstat (limited to 'fs/overlayfs')
-rw-r--r--fs/overlayfs/super.c54
1 files changed, 25 insertions, 29 deletions
diff --git a/fs/overlayfs/super.c b/fs/overlayfs/super.c
index c0463fb80f41..a19fbcde16bd 100644
--- a/fs/overlayfs/super.c
+++ b/fs/overlayfs/super.c
@@ -473,7 +473,9 @@ struct dentry *ovl_lookup(struct inode *dir, struct dentry *dentry,
473 unsigned int ctr = 0; 473 unsigned int ctr = 0;
474 struct inode *inode = NULL; 474 struct inode *inode = NULL;
475 bool upperopaque = false; 475 bool upperopaque = false;
476 struct dentry *this, *prev = NULL; 476 bool stop = false;
477 bool isdir = false;
478 struct dentry *this;
477 unsigned int i; 479 unsigned int i;
478 int err; 480 int err;
479 481
@@ -494,23 +496,26 @@ struct dentry *ovl_lookup(struct inode *dir, struct dentry *dentry,
494 if (ovl_is_whiteout(this)) { 496 if (ovl_is_whiteout(this)) {
495 dput(this); 497 dput(this);
496 this = NULL; 498 this = NULL;
497 upperopaque = true; 499 stop = upperopaque = true;
498 } else if (poe->numlower && ovl_is_opaquedir(this)) { 500 } else if (!d_is_dir(this)) {
499 upperopaque = true; 501 stop = true;
502 } else {
503 isdir = true;
504 if (poe->numlower && ovl_is_opaquedir(this))
505 stop = upperopaque = true;
500 } 506 }
501 } 507 }
502 upperdentry = prev = this; 508 upperdentry = this;
503 } 509 }
504 510
505 if (!upperopaque && poe->numlower) { 511 if (!stop && poe->numlower) {
506 err = -ENOMEM; 512 err = -ENOMEM;
507 stack = kcalloc(poe->numlower, sizeof(struct path), GFP_KERNEL); 513 stack = kcalloc(poe->numlower, sizeof(struct path), GFP_KERNEL);
508 if (!stack) 514 if (!stack)
509 goto out_put_upper; 515 goto out_put_upper;
510 } 516 }
511 517
512 for (i = 0; !upperopaque && i < poe->numlower; i++) { 518 for (i = 0; !stop && i < poe->numlower; i++) {
513 bool opaque = false;
514 struct path lowerpath = poe->lowerstack[i]; 519 struct path lowerpath = poe->lowerstack[i];
515 520
516 this = ovl_lookup_real(lowerpath.dentry, &dentry->d_name); 521 this = ovl_lookup_real(lowerpath.dentry, &dentry->d_name);
@@ -530,35 +535,26 @@ struct dentry *ovl_lookup(struct inode *dir, struct dentry *dentry,
530 break; 535 break;
531 } 536 }
532 /* 537 /*
533 * Only makes sense to check opaque dir if this is not the 538 * If this is a non-directory then stop here.
534 * lowermost layer.
535 */ 539 */
536 if (i < poe->numlower - 1 && ovl_is_opaquedir(this)) 540 if (!d_is_dir(this)) {
537 opaque = true; 541 if (isdir) {
538 542 dput(this);
539 if (prev && (!S_ISDIR(prev->d_inode->i_mode) || 543 break;
540 !S_ISDIR(this->d_inode->i_mode))) { 544 }
545 stop = true;
546 } else {
541 /* 547 /*
542 * FIXME: check for upper-opaqueness maybe better done 548 * Only makes sense to check opaque dir if this is not
543 * in remove code. 549 * the lowermost layer.
544 */ 550 */
545 if (prev == upperdentry) 551 if (i < poe->numlower - 1 && ovl_is_opaquedir(this))
546 upperopaque = true; 552 stop = true;
547 dput(this);
548 break;
549 } 553 }
550 /*
551 * If this is a non-directory then stop here.
552 */
553 if (!S_ISDIR(this->d_inode->i_mode))
554 opaque = true;
555 554
556 stack[ctr].dentry = this; 555 stack[ctr].dentry = this;
557 stack[ctr].mnt = lowerpath.mnt; 556 stack[ctr].mnt = lowerpath.mnt;
558 ctr++; 557 ctr++;
559 prev = this;
560 if (opaque)
561 break;
562 } 558 }
563 559
564 oe = ovl_alloc_entry(ctr); 560 oe = ovl_alloc_entry(ctr);