aboutsummaryrefslogtreecommitdiffstats
path: root/fs/nfs
diff options
context:
space:
mode:
authorPeng Tao <tao.peng@primarydata.com>2014-08-22 05:37:41 -0400
committerTom Haynes <loghyr@primarydata.com>2015-02-03 14:06:39 -0500
commit9bf87482ddc6f8db884177a2a16b1a1dc12f8777 (patch)
tree380c0cc9a14dc4b5492f35473e88aee787b224ff /fs/nfs
parentabb9a0079c7f06360b83a5dd27ce74b8dc6d01b6 (diff)
nfs41: serialize first layoutget of a file
Per RFC 5661 Errata 3208: | A client MAY always forget its layout state and associated | layout stateid at any time (See also section 12.5.5.1). | In such case, the client MUST use a non-layout stateid for the next | LAYOUTGET operation. This will signal the server that the client has | no more layouts on the file and its respective layout state can be | released before issuing a new layout in response to LAYOUTGET. In order to make such a signal unique to server, client needs to serialize all layoutgets using non-layout stateid. We implement this by serializing layoutgets when client has no layout segments at hand. Signed-off-by: Peng Tao <tao.peng@primarydata.com> Signed-off-by: Tom Haynes <Thomas.Haynes@primarydata.com>
Diffstat (limited to 'fs/nfs')
-rw-r--r--fs/nfs/pnfs.c35
-rw-r--r--fs/nfs/pnfs.h1
2 files changed, 32 insertions, 4 deletions
diff --git a/fs/nfs/pnfs.c b/fs/nfs/pnfs.c
index fa00b56f176a..7e1bac189d1c 100644
--- a/fs/nfs/pnfs.c
+++ b/fs/nfs/pnfs.c
@@ -1288,6 +1288,7 @@ pnfs_update_layout(struct inode *ino,
1288 struct nfs_client *clp = server->nfs_client; 1288 struct nfs_client *clp = server->nfs_client;
1289 struct pnfs_layout_hdr *lo; 1289 struct pnfs_layout_hdr *lo;
1290 struct pnfs_layout_segment *lseg = NULL; 1290 struct pnfs_layout_segment *lseg = NULL;
1291 bool first;
1291 1292
1292 if (!pnfs_enabled_sb(NFS_SERVER(ino))) 1293 if (!pnfs_enabled_sb(NFS_SERVER(ino)))
1293 goto out; 1294 goto out;
@@ -1295,6 +1296,8 @@ pnfs_update_layout(struct inode *ino,
1295 if (pnfs_within_mdsthreshold(ctx, ino, iomode)) 1296 if (pnfs_within_mdsthreshold(ctx, ino, iomode))
1296 goto out; 1297 goto out;
1297 1298
1299lookup_again:
1300 first = false;
1298 spin_lock(&ino->i_lock); 1301 spin_lock(&ino->i_lock);
1299 lo = pnfs_find_alloc_layout(ino, ctx, gfp_flags); 1302 lo = pnfs_find_alloc_layout(ino, ctx, gfp_flags);
1300 if (lo == NULL) { 1303 if (lo == NULL) {
@@ -1312,10 +1315,27 @@ pnfs_update_layout(struct inode *ino,
1312 if (pnfs_layout_io_test_failed(lo, iomode)) 1315 if (pnfs_layout_io_test_failed(lo, iomode))
1313 goto out_unlock; 1316 goto out_unlock;
1314 1317
1315 /* Check to see if the layout for the given range already exists */ 1318 first = list_empty(&lo->plh_segs);
1316 lseg = pnfs_find_lseg(lo, &arg); 1319 if (first) {
1317 if (lseg) 1320 /* The first layoutget for the file. Need to serialize per
1318 goto out_unlock; 1321 * RFC 5661 Errata 3208.
1322 */
1323 if (test_and_set_bit(NFS_LAYOUT_FIRST_LAYOUTGET,
1324 &lo->plh_flags)) {
1325 spin_unlock(&ino->i_lock);
1326 wait_on_bit(&lo->plh_flags, NFS_LAYOUT_FIRST_LAYOUTGET,
1327 TASK_UNINTERRUPTIBLE);
1328 pnfs_put_layout_hdr(lo);
1329 goto lookup_again;
1330 }
1331 } else {
1332 /* Check to see if the layout for the given range
1333 * already exists
1334 */
1335 lseg = pnfs_find_lseg(lo, &arg);
1336 if (lseg)
1337 goto out_unlock;
1338 }
1319 1339
1320 if (pnfs_layoutgets_blocked(lo, 0)) 1340 if (pnfs_layoutgets_blocked(lo, 0))
1321 goto out_unlock; 1341 goto out_unlock;
@@ -1343,6 +1363,13 @@ pnfs_update_layout(struct inode *ino,
1343 lseg = send_layoutget(lo, ctx, &arg, gfp_flags); 1363 lseg = send_layoutget(lo, ctx, &arg, gfp_flags);
1344 atomic_dec(&lo->plh_outstanding); 1364 atomic_dec(&lo->plh_outstanding);
1345out_put_layout_hdr: 1365out_put_layout_hdr:
1366 if (first) {
1367 unsigned long *bitlock = &lo->plh_flags;
1368
1369 clear_bit_unlock(NFS_LAYOUT_FIRST_LAYOUTGET, bitlock);
1370 smp_mb__after_atomic();
1371 wake_up_bit(bitlock, NFS_LAYOUT_FIRST_LAYOUTGET);
1372 }
1346 pnfs_put_layout_hdr(lo); 1373 pnfs_put_layout_hdr(lo);
1347out: 1374out:
1348 dprintk("%s: inode %s/%llu pNFS layout segment %s for " 1375 dprintk("%s: inode %s/%llu pNFS layout segment %s for "
diff --git a/fs/nfs/pnfs.h b/fs/nfs/pnfs.h
index c39882191651..4cf0d54e14c3 100644
--- a/fs/nfs/pnfs.h
+++ b/fs/nfs/pnfs.h
@@ -95,6 +95,7 @@ enum {
95 NFS_LAYOUT_ROC, /* some lseg had roc bit set */ 95 NFS_LAYOUT_ROC, /* some lseg had roc bit set */
96 NFS_LAYOUT_RETURN, /* Return this layout ASAP */ 96 NFS_LAYOUT_RETURN, /* Return this layout ASAP */
97 NFS_LAYOUT_INVALID_STID, /* layout stateid id is invalid */ 97 NFS_LAYOUT_INVALID_STID, /* layout stateid id is invalid */
98 NFS_LAYOUT_FIRST_LAYOUTGET, /* Serialize first layoutget */
98}; 99};
99 100
100enum layoutdriver_policy_flags { 101enum layoutdriver_policy_flags {