diff options
| author | Linus Torvalds <torvalds@linux-foundation.org> | 2016-02-03 12:36:41 -0500 |
|---|---|---|
| committer | Linus Torvalds <torvalds@linux-foundation.org> | 2016-02-03 12:36:41 -0500 |
| commit | 81b676bd87b3e098e06295a6dd523c02e7861e88 (patch) | |
| tree | 406f06fbc8e542c8caed8d4cf52773ba0e40efef | |
| parent | ef582d095db13504a54b9bc57c9489e551441c2a (diff) | |
| parent | 2370abdab530718b61afc222c51901bdc2884ee2 (diff) | |
Merge tag 'nfs-for-4.5-3' of git://git.linux-nfs.org/projects/trondmy/linux-nfs
Pull NFS client bugfix and cleanup from Trond Myklebust:
"Bugfix:
- pNFS: Fix for missing layoutreturn calls
Cleanup:
- pNFS: rename NFS_LAYOUT_RETURN_BEFORE_CLOSE for code clarity"
* tag 'nfs-for-4.5-3' of git://git.linux-nfs.org/projects/trondmy/linux-nfs:
NFS: Cleanup - rename NFS_LAYOUT_RETURN_BEFORE_CLOSE
pNFS: Fix missing layoutreturn calls
| -rw-r--r-- | fs/nfs/flexfilelayout/flexfilelayout.c | 2 | ||||
| -rw-r--r-- | fs/nfs/flexfilelayout/flexfilelayoutdev.c | 2 | ||||
| -rw-r--r-- | fs/nfs/pnfs.c | 122 | ||||
| -rw-r--r-- | fs/nfs/pnfs.h | 4 |
4 files changed, 62 insertions, 68 deletions
diff --git a/fs/nfs/flexfilelayout/flexfilelayout.c b/fs/nfs/flexfilelayout/flexfilelayout.c index 5bcd92d50e82..0cb1abd535e3 100644 --- a/fs/nfs/flexfilelayout/flexfilelayout.c +++ b/fs/nfs/flexfilelayout/flexfilelayout.c | |||
| @@ -1215,7 +1215,7 @@ static int ff_layout_read_done_cb(struct rpc_task *task, | |||
| 1215 | hdr->pgio_mirror_idx + 1, | 1215 | hdr->pgio_mirror_idx + 1, |
| 1216 | &hdr->pgio_mirror_idx)) | 1216 | &hdr->pgio_mirror_idx)) |
| 1217 | goto out_eagain; | 1217 | goto out_eagain; |
| 1218 | set_bit(NFS_LAYOUT_RETURN_BEFORE_CLOSE, | 1218 | set_bit(NFS_LAYOUT_RETURN_REQUESTED, |
| 1219 | &hdr->lseg->pls_layout->plh_flags); | 1219 | &hdr->lseg->pls_layout->plh_flags); |
| 1220 | pnfs_read_resend_pnfs(hdr); | 1220 | pnfs_read_resend_pnfs(hdr); |
| 1221 | return task->tk_status; | 1221 | return task->tk_status; |
diff --git a/fs/nfs/flexfilelayout/flexfilelayoutdev.c b/fs/nfs/flexfilelayout/flexfilelayoutdev.c index 29898a9550fa..eb370460ce20 100644 --- a/fs/nfs/flexfilelayout/flexfilelayoutdev.c +++ b/fs/nfs/flexfilelayout/flexfilelayoutdev.c | |||
| @@ -412,7 +412,7 @@ nfs4_ff_layout_prepare_ds(struct pnfs_layout_segment *lseg, u32 ds_idx, | |||
| 412 | OP_ILLEGAL, GFP_NOIO); | 412 | OP_ILLEGAL, GFP_NOIO); |
| 413 | if (!fail_return) { | 413 | if (!fail_return) { |
| 414 | if (ff_layout_has_available_ds(lseg)) | 414 | if (ff_layout_has_available_ds(lseg)) |
| 415 | set_bit(NFS_LAYOUT_RETURN_BEFORE_CLOSE, | 415 | set_bit(NFS_LAYOUT_RETURN_REQUESTED, |
| 416 | &lseg->pls_layout->plh_flags); | 416 | &lseg->pls_layout->plh_flags); |
| 417 | else | 417 | else |
| 418 | pnfs_error_mark_layout_for_return(ino, lseg); | 418 | pnfs_error_mark_layout_for_return(ino, lseg); |
diff --git a/fs/nfs/pnfs.c b/fs/nfs/pnfs.c index a3592cc34a20..482b6e94bb37 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_REQUESTED, &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_REQUESTED, &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_REQUESTED, &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. |
| @@ -1091,7 +1085,7 @@ bool pnfs_roc(struct inode *ino) | |||
| 1091 | 1085 | ||
| 1092 | nfs4_stateid_copy(&stateid, &lo->plh_stateid); | 1086 | nfs4_stateid_copy(&stateid, &lo->plh_stateid); |
| 1093 | /* always send layoutreturn if being marked so */ | 1087 | /* always send layoutreturn if being marked so */ |
| 1094 | if (test_and_clear_bit(NFS_LAYOUT_RETURN_BEFORE_CLOSE, | 1088 | if (test_and_clear_bit(NFS_LAYOUT_RETURN_REQUESTED, |
| 1095 | &lo->plh_flags)) | 1089 | &lo->plh_flags)) |
| 1096 | layoutreturn = pnfs_prepare_layoutreturn(lo); | 1090 | layoutreturn = pnfs_prepare_layoutreturn(lo); |
| 1097 | 1091 | ||
| @@ -1772,7 +1766,7 @@ pnfs_mark_matching_lsegs_return(struct pnfs_layout_hdr *lo, | |||
| 1772 | pnfs_set_plh_return_iomode(lo, return_range->iomode); | 1766 | pnfs_set_plh_return_iomode(lo, return_range->iomode); |
| 1773 | if (!mark_lseg_invalid(lseg, tmp_list)) | 1767 | if (!mark_lseg_invalid(lseg, tmp_list)) |
| 1774 | remaining++; | 1768 | remaining++; |
| 1775 | set_bit(NFS_LAYOUT_RETURN_BEFORE_CLOSE, | 1769 | set_bit(NFS_LAYOUT_RETURN_REQUESTED, |
| 1776 | &lo->plh_flags); | 1770 | &lo->plh_flags); |
| 1777 | } | 1771 | } |
| 1778 | return remaining; | 1772 | return remaining; |
diff --git a/fs/nfs/pnfs.h b/fs/nfs/pnfs.h index 9f4e2a47f4aa..1ac1db5f6dad 100644 --- a/fs/nfs/pnfs.h +++ b/fs/nfs/pnfs.h | |||
| @@ -94,8 +94,8 @@ enum { | |||
| 94 | NFS_LAYOUT_RO_FAILED = 0, /* get ro layout failed stop trying */ | 94 | NFS_LAYOUT_RO_FAILED = 0, /* get ro layout failed stop trying */ |
| 95 | NFS_LAYOUT_RW_FAILED, /* get rw layout failed stop trying */ | 95 | NFS_LAYOUT_RW_FAILED, /* get rw layout failed stop trying */ |
| 96 | NFS_LAYOUT_BULK_RECALL, /* bulk recall affecting layout */ | 96 | NFS_LAYOUT_BULK_RECALL, /* bulk recall affecting layout */ |
| 97 | NFS_LAYOUT_RETURN, /* Return this layout ASAP */ | 97 | NFS_LAYOUT_RETURN, /* layoutreturn in progress */ |
| 98 | NFS_LAYOUT_RETURN_BEFORE_CLOSE, /* Return this layout before close */ | 98 | NFS_LAYOUT_RETURN_REQUESTED, /* Return this layout ASAP */ |
| 99 | NFS_LAYOUT_INVALID_STID, /* layout stateid id is invalid */ | 99 | NFS_LAYOUT_INVALID_STID, /* layout stateid id is invalid */ |
| 100 | NFS_LAYOUT_FIRST_LAYOUTGET, /* Serialize first layoutget */ | 100 | NFS_LAYOUT_FIRST_LAYOUTGET, /* Serialize first layoutget */ |
| 101 | }; | 101 | }; |
