diff options
author | Oleg Drokin <green@linuxhacker.ru> | 2016-07-14 23:40:21 -0400 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2016-08-15 12:25:10 -0400 |
commit | 99f1c013194e64d4b67d5d318148303b0e1585e1 (patch) | |
tree | a47877fd40dd6ca0135b7ef3b18a15ba31906917 | |
parent | 694d0d0bb2030d2e36df73e2d23d5770511dbc8d (diff) |
staging/lustre/llite: Close atomic_open race with several openers
Right now, if it's an open of a negative dentry, a race is possible
with several openers who all try to instantiate/rehash the same
dentry and would hit a BUG_ON in d_add.
But in fact if we got a negative dentry in atomic_open, that means
we just revalidated it so no point in talking to MDS at all,
just return ENOENT and make the race go away completely.
Signed-off-by: Oleg Drokin <green@linuxhacker.ru>
Cc: stable <stable@vger.kernel.org> # 4.7+
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
-rw-r--r-- | drivers/staging/lustre/lustre/llite/namei.c | 43 |
1 files changed, 24 insertions, 19 deletions
diff --git a/drivers/staging/lustre/lustre/llite/namei.c b/drivers/staging/lustre/lustre/llite/namei.c index 3664bfd0178b..2c4dc69731e8 100644 --- a/drivers/staging/lustre/lustre/llite/namei.c +++ b/drivers/staging/lustre/lustre/llite/namei.c | |||
@@ -388,6 +388,7 @@ static int ll_lookup_it_finish(struct ptlrpc_request *request, | |||
388 | struct inode *inode = NULL; | 388 | struct inode *inode = NULL; |
389 | __u64 bits = 0; | 389 | __u64 bits = 0; |
390 | int rc = 0; | 390 | int rc = 0; |
391 | struct dentry *alias; | ||
391 | 392 | ||
392 | /* NB 1 request reference will be taken away by ll_intent_lock() | 393 | /* NB 1 request reference will be taken away by ll_intent_lock() |
393 | * when I return | 394 | * when I return |
@@ -412,26 +413,12 @@ static int ll_lookup_it_finish(struct ptlrpc_request *request, | |||
412 | */ | 413 | */ |
413 | } | 414 | } |
414 | 415 | ||
415 | /* Only hash *de if it is unhashed (new dentry). | 416 | alias = ll_splice_alias(inode, *de); |
416 | * Atoimc_open may passing hashed dentries for open. | 417 | if (IS_ERR(alias)) { |
417 | */ | 418 | rc = PTR_ERR(alias); |
418 | if (d_unhashed(*de)) { | 419 | goto out; |
419 | struct dentry *alias; | ||
420 | |||
421 | alias = ll_splice_alias(inode, *de); | ||
422 | if (IS_ERR(alias)) { | ||
423 | rc = PTR_ERR(alias); | ||
424 | goto out; | ||
425 | } | ||
426 | *de = alias; | ||
427 | } else if (!it_disposition(it, DISP_LOOKUP_NEG) && | ||
428 | !it_disposition(it, DISP_OPEN_CREATE)) { | ||
429 | /* With DISP_OPEN_CREATE dentry will be | ||
430 | * instantiated in ll_create_it. | ||
431 | */ | ||
432 | LASSERT(!d_inode(*de)); | ||
433 | d_instantiate(*de, inode); | ||
434 | } | 420 | } |
421 | *de = alias; | ||
435 | 422 | ||
436 | if (!it_disposition(it, DISP_LOOKUP_NEG)) { | 423 | if (!it_disposition(it, DISP_LOOKUP_NEG)) { |
437 | /* we have lookup look - unhide dentry */ | 424 | /* we have lookup look - unhide dentry */ |
@@ -587,6 +574,24 @@ static int ll_atomic_open(struct inode *dir, struct dentry *dentry, | |||
587 | dentry, PFID(ll_inode2fid(dir)), dir, file, open_flags, mode, | 574 | dentry, PFID(ll_inode2fid(dir)), dir, file, open_flags, mode, |
588 | *opened); | 575 | *opened); |
589 | 576 | ||
577 | /* Only negative dentries enter here */ | ||
578 | LASSERT(!d_inode(dentry)); | ||
579 | |||
580 | if (!d_in_lookup(dentry)) { | ||
581 | /* A valid negative dentry that just passed revalidation, | ||
582 | * there's little point to try and open it server-side, | ||
583 | * even though there's a minuscle chance it might succeed. | ||
584 | * Either way it's a valid race to just return -ENOENT here. | ||
585 | */ | ||
586 | if (!(open_flags & O_CREAT)) | ||
587 | return -ENOENT; | ||
588 | |||
589 | /* Otherwise we just unhash it to be rehashed afresh via | ||
590 | * lookup if necessary | ||
591 | */ | ||
592 | d_drop(dentry); | ||
593 | } | ||
594 | |||
590 | it = kzalloc(sizeof(*it), GFP_NOFS); | 595 | it = kzalloc(sizeof(*it), GFP_NOFS); |
591 | if (!it) | 596 | if (!it) |
592 | return -ENOMEM; | 597 | return -ENOMEM; |