diff options
author | Peng Tao <tao.peng@primarydata.com> | 2014-11-30 19:22:23 -0500 |
---|---|---|
committer | Tom Haynes <loghyr@primarydata.com> | 2015-02-03 14:06:51 -0500 |
commit | aa8a45ee974dfe3ffe290daaf5db457afae56fde (patch) | |
tree | 10d2b6eb4a9530f2d1a3433627b401d907c3bdb7 | |
parent | 012fa16dca0da6c487dd066829ff0b0954925fe6 (diff) |
nfs41: wait for LAYOUTRETURN before retrying LAYOUTGET
Also take care to stop waiting if someone clears retry bit.
Signed-off-by: Peng Tao <tao.peng@primarydata.com>
-rw-r--r-- | fs/nfs/nfs4proc.c | 4 | ||||
-rw-r--r-- | fs/nfs/pnfs.c | 39 | ||||
-rw-r--r-- | fs/nfs/pnfs.h | 5 |
3 files changed, 45 insertions, 3 deletions
diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index 7e1a97a54f99..44c600aac907 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c | |||
@@ -7796,7 +7796,9 @@ static void nfs4_layoutreturn_release(void *calldata) | |||
7796 | spin_lock(&lo->plh_inode->i_lock); | 7796 | spin_lock(&lo->plh_inode->i_lock); |
7797 | if (lrp->res.lrs_present) | 7797 | if (lrp->res.lrs_present) |
7798 | pnfs_set_layout_stateid(lo, &lrp->res.stateid, true); | 7798 | pnfs_set_layout_stateid(lo, &lrp->res.stateid, true); |
7799 | clear_bit(NFS_LAYOUT_RETURN, &lo->plh_flags); | 7799 | clear_bit_unlock(NFS_LAYOUT_RETURN, &lo->plh_flags); |
7800 | smp_mb__after_atomic(); | ||
7801 | wake_up_bit(&lo->plh_flags, NFS_LAYOUT_RETURN); | ||
7800 | clear_bit(NFS_LAYOUT_RETURN_BEFORE_CLOSE, &lo->plh_flags); | 7802 | clear_bit(NFS_LAYOUT_RETURN_BEFORE_CLOSE, &lo->plh_flags); |
7801 | rpc_wake_up(&NFS_SERVER(lo->plh_inode)->roc_rpcwaitq); | 7803 | rpc_wake_up(&NFS_SERVER(lo->plh_inode)->roc_rpcwaitq); |
7802 | lo->plh_block_lgets--; | 7804 | lo->plh_block_lgets--; |
diff --git a/fs/nfs/pnfs.c b/fs/nfs/pnfs.c index 893f6b5afe6a..c4c9fe606ae6 100644 --- a/fs/nfs/pnfs.c +++ b/fs/nfs/pnfs.c | |||
@@ -1398,6 +1398,26 @@ static bool pnfs_within_mdsthreshold(struct nfs_open_context *ctx, | |||
1398 | return ret; | 1398 | return ret; |
1399 | } | 1399 | } |
1400 | 1400 | ||
1401 | /* stop waiting if someone clears NFS_LAYOUT_RETRY_LAYOUTGET bit. */ | ||
1402 | static int pnfs_layoutget_retry_bit_wait(struct wait_bit_key *key) | ||
1403 | { | ||
1404 | if (!test_bit(NFS_LAYOUT_RETRY_LAYOUTGET, key->flags)) | ||
1405 | return 1; | ||
1406 | return nfs_wait_bit_killable(key); | ||
1407 | } | ||
1408 | |||
1409 | static bool pnfs_prepare_to_retry_layoutget(struct pnfs_layout_hdr *lo) | ||
1410 | { | ||
1411 | /* | ||
1412 | * send layoutcommit as it can hold up layoutreturn due to lseg | ||
1413 | * reference | ||
1414 | */ | ||
1415 | pnfs_layoutcommit_inode(lo->plh_inode, false); | ||
1416 | return !wait_on_bit_action(&lo->plh_flags, NFS_LAYOUT_RETURN, | ||
1417 | pnfs_layoutget_retry_bit_wait, | ||
1418 | TASK_UNINTERRUPTIBLE); | ||
1419 | } | ||
1420 | |||
1401 | /* | 1421 | /* |
1402 | * Layout segment is retreived from the server if not cached. | 1422 | * Layout segment is retreived from the server if not cached. |
1403 | * The appropriate layout segment is referenced and returned to the caller. | 1423 | * The appropriate layout segment is referenced and returned to the caller. |
@@ -1444,7 +1464,8 @@ lookup_again: | |||
1444 | } | 1464 | } |
1445 | 1465 | ||
1446 | /* if LAYOUTGET already failed once we don't try again */ | 1466 | /* if LAYOUTGET already failed once we don't try again */ |
1447 | if (pnfs_layout_io_test_failed(lo, iomode)) | 1467 | if (pnfs_layout_io_test_failed(lo, iomode) && |
1468 | !pnfs_should_retry_layoutget(lo)) | ||
1448 | goto out_unlock; | 1469 | goto out_unlock; |
1449 | 1470 | ||
1450 | first = list_empty(&lo->plh_segs); | 1471 | first = list_empty(&lo->plh_segs); |
@@ -1469,6 +1490,22 @@ lookup_again: | |||
1469 | goto out_unlock; | 1490 | goto out_unlock; |
1470 | } | 1491 | } |
1471 | 1492 | ||
1493 | /* | ||
1494 | * Because we free lsegs before sending LAYOUTRETURN, we need to wait | ||
1495 | * for LAYOUTRETURN even if first is true. | ||
1496 | */ | ||
1497 | if (!lseg && pnfs_should_retry_layoutget(lo) && | ||
1498 | test_bit(NFS_LAYOUT_RETURN, &lo->plh_flags)) { | ||
1499 | spin_unlock(&ino->i_lock); | ||
1500 | dprintk("%s wait for layoutreturn\n", __func__); | ||
1501 | if (pnfs_prepare_to_retry_layoutget(lo)) { | ||
1502 | pnfs_put_layout_hdr(lo); | ||
1503 | dprintk("%s retrying\n", __func__); | ||
1504 | goto lookup_again; | ||
1505 | } | ||
1506 | goto out_put_layout_hdr; | ||
1507 | } | ||
1508 | |||
1472 | if (pnfs_layoutgets_blocked(lo, &arg, 0)) | 1509 | if (pnfs_layoutgets_blocked(lo, &arg, 0)) |
1473 | goto out_unlock; | 1510 | goto out_unlock; |
1474 | atomic_inc(&lo->plh_outstanding); | 1511 | atomic_inc(&lo->plh_outstanding); |
diff --git a/fs/nfs/pnfs.h b/fs/nfs/pnfs.h index fed6ae067acb..49a466708400 100644 --- a/fs/nfs/pnfs.h +++ b/fs/nfs/pnfs.h | |||
@@ -359,8 +359,11 @@ static inline void pnfs_set_retry_layoutget(struct pnfs_layout_hdr *lo) | |||
359 | 359 | ||
360 | static inline void pnfs_clear_retry_layoutget(struct pnfs_layout_hdr *lo) | 360 | static inline void pnfs_clear_retry_layoutget(struct pnfs_layout_hdr *lo) |
361 | { | 361 | { |
362 | if (test_and_clear_bit(NFS_LAYOUT_RETRY_LAYOUTGET, &lo->plh_flags)) | 362 | if (test_and_clear_bit(NFS_LAYOUT_RETRY_LAYOUTGET, &lo->plh_flags)) { |
363 | atomic_dec(&lo->plh_refcount); | 363 | atomic_dec(&lo->plh_refcount); |
364 | /* wake up waiters for LAYOUTRETURN as that is not needed */ | ||
365 | wake_up_bit(&lo->plh_flags, NFS_LAYOUT_RETURN); | ||
366 | } | ||
364 | } | 367 | } |
365 | 368 | ||
366 | static inline bool pnfs_should_retry_layoutget(struct pnfs_layout_hdr *lo) | 369 | static inline bool pnfs_should_retry_layoutget(struct pnfs_layout_hdr *lo) |