diff options
author | Trond Myklebust <trond.myklebust@primarydata.com> | 2016-01-26 23:12:11 -0500 |
---|---|---|
committer | Trond Myklebust <trond.myklebust@primarydata.com> | 2016-01-26 23:12:11 -0500 |
commit | 13c13a6ad71f98c3b6189dfc89a9a743ab02a39a (patch) | |
tree | 8ad5d6ec00251a0e8219da0e3735d82b57736154 | |
parent | 92e963f50fc74041b5e9e744c330dca48e04f08d (diff) |
pNFS: Fix missing layoutreturn calls
The layoutreturn code currently relies on pnfs_put_lseg() to initiate the
RPC call when conditions are right. A problem arises when we want to
free the layout segment from inside an inode->i_lock section (e.g. in
pnfs_clear_request_commit()), since we cannot sleep.
The workaround is to move the actual call to pnfs_send_layoutreturn()
to pnfs_put_layout_hdr(), which doesn't have this restriction.
Signed-off-by: Trond Myklebust <trond.myklebust@primarydata.com>
-rw-r--r-- | fs/nfs/pnfs.c | 118 |
1 files changed, 56 insertions, 62 deletions
diff --git a/fs/nfs/pnfs.c b/fs/nfs/pnfs.c index a3592cc34a20..9c20685d4961 100644 --- a/fs/nfs/pnfs.c +++ b/fs/nfs/pnfs.c | |||
@@ -52,9 +52,7 @@ static DEFINE_SPINLOCK(pnfs_spinlock); | |||
52 | */ | 52 | */ |
53 | static LIST_HEAD(pnfs_modules_tbl); | 53 | static LIST_HEAD(pnfs_modules_tbl); |
54 | 54 | ||
55 | static int | 55 | static void pnfs_layoutreturn_before_put_layout_hdr(struct pnfs_layout_hdr *lo); |
56 | pnfs_send_layoutreturn(struct pnfs_layout_hdr *lo, const nfs4_stateid *stateid, | ||
57 | enum pnfs_iomode iomode, bool sync); | ||
58 | 56 | ||
59 | /* Return the registered pnfs layout driver module matching given id */ | 57 | /* Return the registered pnfs layout driver module matching given id */ |
60 | static struct pnfs_layoutdriver_type * | 58 | static struct pnfs_layoutdriver_type * |
@@ -243,6 +241,8 @@ pnfs_put_layout_hdr(struct pnfs_layout_hdr *lo) | |||
243 | { | 241 | { |
244 | struct inode *inode = lo->plh_inode; | 242 | struct inode *inode = lo->plh_inode; |
245 | 243 | ||
244 | pnfs_layoutreturn_before_put_layout_hdr(lo); | ||
245 | |||
246 | if (atomic_dec_and_lock(&lo->plh_refcount, &inode->i_lock)) { | 246 | if (atomic_dec_and_lock(&lo->plh_refcount, &inode->i_lock)) { |
247 | if (!list_empty(&lo->plh_segs)) | 247 | if (!list_empty(&lo->plh_segs)) |
248 | WARN_ONCE(1, "NFS: BUG unfreed layout segments.\n"); | 248 | WARN_ONCE(1, "NFS: BUG unfreed layout segments.\n"); |
@@ -345,58 +345,6 @@ pnfs_layout_remove_lseg(struct pnfs_layout_hdr *lo, | |||
345 | rpc_wake_up(&NFS_SERVER(inode)->roc_rpcwaitq); | 345 | rpc_wake_up(&NFS_SERVER(inode)->roc_rpcwaitq); |
346 | } | 346 | } |
347 | 347 | ||
348 | /* Return true if layoutreturn is needed */ | ||
349 | static bool | ||
350 | pnfs_layout_need_return(struct pnfs_layout_hdr *lo, | ||
351 | struct pnfs_layout_segment *lseg) | ||
352 | { | ||
353 | struct pnfs_layout_segment *s; | ||
354 | |||
355 | if (!test_and_clear_bit(NFS_LSEG_LAYOUTRETURN, &lseg->pls_flags)) | ||
356 | return false; | ||
357 | |||
358 | list_for_each_entry(s, &lo->plh_segs, pls_list) | ||
359 | if (s != lseg && test_bit(NFS_LSEG_LAYOUTRETURN, &s->pls_flags)) | ||
360 | return false; | ||
361 | |||
362 | return true; | ||
363 | } | ||
364 | |||
365 | static bool | ||
366 | pnfs_prepare_layoutreturn(struct pnfs_layout_hdr *lo) | ||
367 | { | ||
368 | if (test_and_set_bit(NFS_LAYOUT_RETURN, &lo->plh_flags)) | ||
369 | return false; | ||
370 | lo->plh_return_iomode = 0; | ||
371 | pnfs_get_layout_hdr(lo); | ||
372 | clear_bit(NFS_LAYOUT_RETURN_BEFORE_CLOSE, &lo->plh_flags); | ||
373 | return true; | ||
374 | } | ||
375 | |||
376 | static void pnfs_layoutreturn_before_put_lseg(struct pnfs_layout_segment *lseg, | ||
377 | struct pnfs_layout_hdr *lo, struct inode *inode) | ||
378 | { | ||
379 | lo = lseg->pls_layout; | ||
380 | inode = lo->plh_inode; | ||
381 | |||
382 | spin_lock(&inode->i_lock); | ||
383 | if (pnfs_layout_need_return(lo, lseg)) { | ||
384 | nfs4_stateid stateid; | ||
385 | enum pnfs_iomode iomode; | ||
386 | bool send; | ||
387 | |||
388 | nfs4_stateid_copy(&stateid, &lo->plh_stateid); | ||
389 | iomode = lo->plh_return_iomode; | ||
390 | send = pnfs_prepare_layoutreturn(lo); | ||
391 | spin_unlock(&inode->i_lock); | ||
392 | if (send) { | ||
393 | /* Send an async layoutreturn so we dont deadlock */ | ||
394 | pnfs_send_layoutreturn(lo, &stateid, iomode, false); | ||
395 | } | ||
396 | } else | ||
397 | spin_unlock(&inode->i_lock); | ||
398 | } | ||
399 | |||
400 | void | 348 | void |
401 | pnfs_put_lseg(struct pnfs_layout_segment *lseg) | 349 | pnfs_put_lseg(struct pnfs_layout_segment *lseg) |
402 | { | 350 | { |
@@ -410,15 +358,8 @@ pnfs_put_lseg(struct pnfs_layout_segment *lseg) | |||
410 | atomic_read(&lseg->pls_refcount), | 358 | atomic_read(&lseg->pls_refcount), |
411 | test_bit(NFS_LSEG_VALID, &lseg->pls_flags)); | 359 | test_bit(NFS_LSEG_VALID, &lseg->pls_flags)); |
412 | 360 | ||
413 | /* Handle the case where refcount != 1 */ | ||
414 | if (atomic_add_unless(&lseg->pls_refcount, -1, 1)) | ||
415 | return; | ||
416 | |||
417 | lo = lseg->pls_layout; | 361 | lo = lseg->pls_layout; |
418 | inode = lo->plh_inode; | 362 | inode = lo->plh_inode; |
419 | /* Do we need a layoutreturn? */ | ||
420 | if (test_bit(NFS_LSEG_LAYOUTRETURN, &lseg->pls_flags)) | ||
421 | pnfs_layoutreturn_before_put_lseg(lseg, lo, inode); | ||
422 | 363 | ||
423 | if (atomic_dec_and_lock(&lseg->pls_refcount, &inode->i_lock)) { | 364 | if (atomic_dec_and_lock(&lseg->pls_refcount, &inode->i_lock)) { |
424 | if (test_bit(NFS_LSEG_VALID, &lseg->pls_flags)) { | 365 | if (test_bit(NFS_LSEG_VALID, &lseg->pls_flags)) { |
@@ -937,6 +878,17 @@ void pnfs_clear_layoutreturn_waitbit(struct pnfs_layout_hdr *lo) | |||
937 | rpc_wake_up(&NFS_SERVER(lo->plh_inode)->roc_rpcwaitq); | 878 | rpc_wake_up(&NFS_SERVER(lo->plh_inode)->roc_rpcwaitq); |
938 | } | 879 | } |
939 | 880 | ||
881 | static bool | ||
882 | pnfs_prepare_layoutreturn(struct pnfs_layout_hdr *lo) | ||
883 | { | ||
884 | if (test_and_set_bit(NFS_LAYOUT_RETURN, &lo->plh_flags)) | ||
885 | return false; | ||
886 | lo->plh_return_iomode = 0; | ||
887 | pnfs_get_layout_hdr(lo); | ||
888 | clear_bit(NFS_LAYOUT_RETURN_BEFORE_CLOSE, &lo->plh_flags); | ||
889 | return true; | ||
890 | } | ||
891 | |||
940 | static int | 892 | static int |
941 | pnfs_send_layoutreturn(struct pnfs_layout_hdr *lo, const nfs4_stateid *stateid, | 893 | pnfs_send_layoutreturn(struct pnfs_layout_hdr *lo, const nfs4_stateid *stateid, |
942 | enum pnfs_iomode iomode, bool sync) | 894 | enum pnfs_iomode iomode, bool sync) |
@@ -971,6 +923,48 @@ out: | |||
971 | return status; | 923 | return status; |
972 | } | 924 | } |
973 | 925 | ||
926 | /* Return true if layoutreturn is needed */ | ||
927 | static bool | ||
928 | pnfs_layout_need_return(struct pnfs_layout_hdr *lo) | ||
929 | { | ||
930 | struct pnfs_layout_segment *s; | ||
931 | |||
932 | if (!test_bit(NFS_LAYOUT_RETURN_BEFORE_CLOSE, &lo->plh_flags)) | ||
933 | return false; | ||
934 | |||
935 | /* Defer layoutreturn until all lsegs are done */ | ||
936 | list_for_each_entry(s, &lo->plh_segs, pls_list) { | ||
937 | if (test_bit(NFS_LSEG_LAYOUTRETURN, &s->pls_flags)) | ||
938 | return false; | ||
939 | } | ||
940 | |||
941 | return true; | ||
942 | } | ||
943 | |||
944 | static void pnfs_layoutreturn_before_put_layout_hdr(struct pnfs_layout_hdr *lo) | ||
945 | { | ||
946 | struct inode *inode= lo->plh_inode; | ||
947 | |||
948 | if (!test_bit(NFS_LAYOUT_RETURN_BEFORE_CLOSE, &lo->plh_flags)) | ||
949 | return; | ||
950 | spin_lock(&inode->i_lock); | ||
951 | if (pnfs_layout_need_return(lo)) { | ||
952 | nfs4_stateid stateid; | ||
953 | enum pnfs_iomode iomode; | ||
954 | bool send; | ||
955 | |||
956 | nfs4_stateid_copy(&stateid, &lo->plh_stateid); | ||
957 | iomode = lo->plh_return_iomode; | ||
958 | send = pnfs_prepare_layoutreturn(lo); | ||
959 | spin_unlock(&inode->i_lock); | ||
960 | if (send) { | ||
961 | /* Send an async layoutreturn so we dont deadlock */ | ||
962 | pnfs_send_layoutreturn(lo, &stateid, iomode, false); | ||
963 | } | ||
964 | } else | ||
965 | spin_unlock(&inode->i_lock); | ||
966 | } | ||
967 | |||
974 | /* | 968 | /* |
975 | * Initiates a LAYOUTRETURN(FILE), and removes the pnfs_layout_hdr | 969 | * Initiates a LAYOUTRETURN(FILE), and removes the pnfs_layout_hdr |
976 | * when the layout segment list is empty. | 970 | * when the layout segment list is empty. |