diff options
author | Fred Isaman <iisaman@netapp.com> | 2011-02-03 13:28:50 -0500 |
---|---|---|
committer | Trond Myklebust <Trond.Myklebust@netapp.com> | 2011-03-11 15:38:39 -0500 |
commit | 38511722446993d926861696194c39ef135d85a4 (patch) | |
tree | 56ca01a34aea70cfc3473996bd3712cda3022166 /fs/nfs | |
parent | 53d4737580535e073963b91ce87d4216e434fab5 (diff) |
pnfs: avoid incorrect use of layout stateid
The code could violate the following from RFC5661, section 12.5.3:
"Once a client has no more layouts on a file, the layout stateid is no
longer valid and MUST NOT be used."
This can occur when a layout already has a lseg, starts another
non-everlapping LAYOUTGET, and a CB_LAYOUTRECALL for the existing lseg
is processed before we hit pnfs_layout_process().
Solve by setting, each time the client has no more lsegs for a file, a
flag which blocks further use of the layout and triggers its removal.
This also fixes a second bug which occurs in the same instance as
above. If we actually use pnfs_layout_process, we add the new lseg to
the layout, but the layout has been removed from the nfs_client list
by the intervening CB_LAYOUTRECALL and will not be added back. Thus
the newly acquired lseg will not be properly returned in the event of
a subsequent CB_LAYOUTRECALL.
Signed-off-by: Fred Isaman <iisaman@netapp.com>
Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
Diffstat (limited to 'fs/nfs')
-rw-r--r-- | fs/nfs/pnfs.c | 13 |
1 files changed, 10 insertions, 3 deletions
diff --git a/fs/nfs/pnfs.c b/fs/nfs/pnfs.c index 1b1bc1a0fb0a..c8d9b2148cb1 100644 --- a/fs/nfs/pnfs.c +++ b/fs/nfs/pnfs.c | |||
@@ -255,6 +255,9 @@ put_lseg_locked(struct pnfs_layout_segment *lseg, | |||
255 | list_del_init(&lseg->pls_layout->plh_layouts); | 255 | list_del_init(&lseg->pls_layout->plh_layouts); |
256 | spin_unlock(&clp->cl_lock); | 256 | spin_unlock(&clp->cl_lock); |
257 | clear_bit(NFS_LAYOUT_BULK_RECALL, &lseg->pls_layout->plh_flags); | 257 | clear_bit(NFS_LAYOUT_BULK_RECALL, &lseg->pls_layout->plh_flags); |
258 | set_bit(NFS_LAYOUT_DESTROYED, &lseg->pls_layout->plh_flags); | ||
259 | /* Matched by initial refcount set in alloc_init_layout_hdr */ | ||
260 | put_layout_hdr_locked(lseg->pls_layout); | ||
258 | } | 261 | } |
259 | rpc_wake_up(&NFS_SERVER(ino)->roc_rpcwaitq); | 262 | rpc_wake_up(&NFS_SERVER(ino)->roc_rpcwaitq); |
260 | list_add(&lseg->pls_list, tmp_list); | 263 | list_add(&lseg->pls_list, tmp_list); |
@@ -299,6 +302,11 @@ mark_matching_lsegs_invalid(struct pnfs_layout_hdr *lo, | |||
299 | 302 | ||
300 | dprintk("%s:Begin lo %p\n", __func__, lo); | 303 | dprintk("%s:Begin lo %p\n", __func__, lo); |
301 | 304 | ||
305 | if (list_empty(&lo->plh_segs)) { | ||
306 | if (!test_and_set_bit(NFS_LAYOUT_DESTROYED, &lo->plh_flags)) | ||
307 | put_layout_hdr_locked(lo); | ||
308 | return 0; | ||
309 | } | ||
302 | list_for_each_entry_safe(lseg, next, &lo->plh_segs, pls_list) | 310 | list_for_each_entry_safe(lseg, next, &lo->plh_segs, pls_list) |
303 | if (should_free_lseg(lseg->pls_range.iomode, iomode)) { | 311 | if (should_free_lseg(lseg->pls_range.iomode, iomode)) { |
304 | dprintk("%s: freeing lseg %p iomode %d " | 312 | dprintk("%s: freeing lseg %p iomode %d " |
@@ -332,10 +340,8 @@ pnfs_destroy_layout(struct nfs_inode *nfsi) | |||
332 | spin_lock(&nfsi->vfs_inode.i_lock); | 340 | spin_lock(&nfsi->vfs_inode.i_lock); |
333 | lo = nfsi->layout; | 341 | lo = nfsi->layout; |
334 | if (lo) { | 342 | if (lo) { |
335 | set_bit(NFS_LAYOUT_DESTROYED, &nfsi->layout->plh_flags); | 343 | lo->plh_block_lgets++; /* permanently block new LAYOUTGETs */ |
336 | mark_matching_lsegs_invalid(lo, &tmp_list, IOMODE_ANY); | 344 | mark_matching_lsegs_invalid(lo, &tmp_list, IOMODE_ANY); |
337 | /* Matched by refcount set to 1 in alloc_init_layout_hdr */ | ||
338 | put_layout_hdr_locked(lo); | ||
339 | } | 345 | } |
340 | spin_unlock(&nfsi->vfs_inode.i_lock); | 346 | spin_unlock(&nfsi->vfs_inode.i_lock); |
341 | pnfs_free_lseg_list(&tmp_list); | 347 | pnfs_free_lseg_list(&tmp_list); |
@@ -403,6 +409,7 @@ pnfs_layoutgets_blocked(struct pnfs_layout_hdr *lo, nfs4_stateid *stateid, | |||
403 | (int)(lo->plh_barrier - be32_to_cpu(stateid->stateid.seqid)) >= 0) | 409 | (int)(lo->plh_barrier - be32_to_cpu(stateid->stateid.seqid)) >= 0) |
404 | return true; | 410 | return true; |
405 | return lo->plh_block_lgets || | 411 | return lo->plh_block_lgets || |
412 | test_bit(NFS_LAYOUT_DESTROYED, &lo->plh_flags) || | ||
406 | test_bit(NFS_LAYOUT_BULK_RECALL, &lo->plh_flags) || | 413 | test_bit(NFS_LAYOUT_BULK_RECALL, &lo->plh_flags) || |
407 | (list_empty(&lo->plh_segs) && | 414 | (list_empty(&lo->plh_segs) && |
408 | (atomic_read(&lo->plh_outstanding) > lget)); | 415 | (atomic_read(&lo->plh_outstanding) > lget)); |