diff options
author | Trond Myklebust <trond.myklebust@primarydata.com> | 2014-02-12 10:02:27 -0500 |
---|---|---|
committer | Trond Myklebust <trond.myklebust@primarydata.com> | 2014-02-19 21:21:06 -0500 |
commit | 78096ccac561ce2d89fbff1d1aa451bf4090a1a2 (patch) | |
tree | 16c4a56dedb1d8f929713268019333b999737beb /fs/nfs | |
parent | 9a7fe9e8900baad5f6643000ea48b91aee895165 (diff) |
NFSv4.1: Ensure that we free existing layout segments if we get a new layout
If the server returns a completely new layout stateid in response to our
LAYOUTGET, then make sure to free any existing layout segments.
Signed-off-by: Trond Myklebust <trond.myklebust@primarydata.com>
Diffstat (limited to 'fs/nfs')
-rw-r--r-- | fs/nfs/pnfs.c | 15 |
1 files changed, 15 insertions, 0 deletions
diff --git a/fs/nfs/pnfs.c b/fs/nfs/pnfs.c index 6e67ada6c22c..cb53d450ae32 100644 --- a/fs/nfs/pnfs.c +++ b/fs/nfs/pnfs.c | |||
@@ -665,6 +665,17 @@ static bool pnfs_seqid_is_newer(u32 s1, u32 s2) | |||
665 | return (s32)(s1 - s2) > 0; | 665 | return (s32)(s1 - s2) > 0; |
666 | } | 666 | } |
667 | 667 | ||
668 | static void | ||
669 | pnfs_verify_layout_stateid(struct pnfs_layout_hdr *lo, | ||
670 | const nfs4_stateid *new, | ||
671 | struct list_head *free_me_list) | ||
672 | { | ||
673 | if (nfs4_stateid_match_other(&lo->plh_stateid, new)) | ||
674 | return; | ||
675 | /* Layout is new! Kill existing layout segments */ | ||
676 | pnfs_mark_matching_lsegs_invalid(lo, free_me_list, NULL); | ||
677 | } | ||
678 | |||
668 | /* update lo->plh_stateid with new if is more recent */ | 679 | /* update lo->plh_stateid with new if is more recent */ |
669 | void | 680 | void |
670 | pnfs_set_layout_stateid(struct pnfs_layout_hdr *lo, const nfs4_stateid *new, | 681 | pnfs_set_layout_stateid(struct pnfs_layout_hdr *lo, const nfs4_stateid *new, |
@@ -1315,6 +1326,7 @@ pnfs_layout_process(struct nfs4_layoutget *lgp) | |||
1315 | struct nfs4_layoutget_res *res = &lgp->res; | 1326 | struct nfs4_layoutget_res *res = &lgp->res; |
1316 | struct pnfs_layout_segment *lseg; | 1327 | struct pnfs_layout_segment *lseg; |
1317 | struct inode *ino = lo->plh_inode; | 1328 | struct inode *ino = lo->plh_inode; |
1329 | LIST_HEAD(free_me); | ||
1318 | int status = 0; | 1330 | int status = 0; |
1319 | 1331 | ||
1320 | /* Inject layout blob into I/O device driver */ | 1332 | /* Inject layout blob into I/O device driver */ |
@@ -1341,6 +1353,8 @@ pnfs_layout_process(struct nfs4_layoutget *lgp) | |||
1341 | goto out_forget_reply; | 1353 | goto out_forget_reply; |
1342 | } | 1354 | } |
1343 | 1355 | ||
1356 | /* Check that the new stateid matches the old stateid */ | ||
1357 | pnfs_verify_layout_stateid(lo, &res->stateid, &free_me); | ||
1344 | /* Done processing layoutget. Set the layout stateid */ | 1358 | /* Done processing layoutget. Set the layout stateid */ |
1345 | pnfs_set_layout_stateid(lo, &res->stateid, false); | 1359 | pnfs_set_layout_stateid(lo, &res->stateid, false); |
1346 | 1360 | ||
@@ -1355,6 +1369,7 @@ pnfs_layout_process(struct nfs4_layoutget *lgp) | |||
1355 | } | 1369 | } |
1356 | 1370 | ||
1357 | spin_unlock(&ino->i_lock); | 1371 | spin_unlock(&ino->i_lock); |
1372 | pnfs_free_lseg_list(&free_me); | ||
1358 | return lseg; | 1373 | return lseg; |
1359 | out: | 1374 | out: |
1360 | return ERR_PTR(status); | 1375 | return ERR_PTR(status); |