diff options
author | Peng Tao <tao.peng@primarydata.com> | 2014-09-05 12:53:23 -0400 |
---|---|---|
committer | Tom Haynes <loghyr@primarydata.com> | 2015-02-03 14:06:41 -0500 |
commit | 016256df3a7e9eeb3f4dea5ccd0e21a0b63841eb (patch) | |
tree | 98a9c9596f3febafdbaeff99e6912f8b295dd897 /fs/nfs | |
parent | f40eb5d044e2eea3f866eeeeb45ca30753773cda (diff) |
nfs41: add a helper to mark layout for return
It marks all matching layout segments as NFS_LSEG_LAYOUTRETURN,
which is an indicator for pnfs_put_lseg() to send layoutreturn,
and also prevents pnfs_update_layout() from using the returning
segments. Once it is set, it never gets cleared.
It also sets proper io failure bit so that pnfs path can be retried
after PNFS_LAYOUTGET_RETRY_TIMEOUT second.
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.c | 55 | ||||
-rw-r--r-- | fs/nfs/pnfs.h | 4 |
2 files changed, 59 insertions, 0 deletions
diff --git a/fs/nfs/pnfs.c b/fs/nfs/pnfs.c index 1b9720992608..0bd149baca71 100644 --- a/fs/nfs/pnfs.c +++ b/fs/nfs/pnfs.c | |||
@@ -1479,6 +1479,61 @@ out_forget_reply: | |||
1479 | goto out; | 1479 | goto out; |
1480 | } | 1480 | } |
1481 | 1481 | ||
1482 | static void | ||
1483 | pnfs_mark_matching_lsegs_return(struct pnfs_layout_hdr *lo, | ||
1484 | struct list_head *tmp_list, | ||
1485 | struct pnfs_layout_range *return_range) | ||
1486 | { | ||
1487 | struct pnfs_layout_segment *lseg, *next; | ||
1488 | |||
1489 | dprintk("%s:Begin lo %p\n", __func__, lo); | ||
1490 | |||
1491 | if (list_empty(&lo->plh_segs)) | ||
1492 | return; | ||
1493 | |||
1494 | list_for_each_entry_safe(lseg, next, &lo->plh_segs, pls_list) | ||
1495 | if (should_free_lseg(&lseg->pls_range, return_range)) { | ||
1496 | dprintk("%s: marking lseg %p iomode %d " | ||
1497 | "offset %llu length %llu\n", __func__, | ||
1498 | lseg, lseg->pls_range.iomode, | ||
1499 | lseg->pls_range.offset, | ||
1500 | lseg->pls_range.length); | ||
1501 | set_bit(NFS_LSEG_LAYOUTRETURN, &lseg->pls_flags); | ||
1502 | mark_lseg_invalid(lseg, tmp_list); | ||
1503 | } | ||
1504 | } | ||
1505 | |||
1506 | void pnfs_error_mark_layout_for_return(struct inode *inode, | ||
1507 | struct pnfs_layout_segment *lseg) | ||
1508 | { | ||
1509 | struct pnfs_layout_hdr *lo = NFS_I(inode)->layout; | ||
1510 | int iomode = pnfs_iomode_to_fail_bit(lseg->pls_range.iomode); | ||
1511 | struct pnfs_layout_range range = { | ||
1512 | .iomode = lseg->pls_range.iomode, | ||
1513 | .offset = 0, | ||
1514 | .length = NFS4_MAX_UINT64, | ||
1515 | }; | ||
1516 | LIST_HEAD(free_me); | ||
1517 | |||
1518 | spin_lock(&inode->i_lock); | ||
1519 | /* set failure bit so that pnfs path will be retried later */ | ||
1520 | pnfs_layout_set_fail_bit(lo, iomode); | ||
1521 | set_bit(NFS_LAYOUT_RETURN, &lo->plh_flags); | ||
1522 | if (lo->plh_return_iomode == 0) | ||
1523 | lo->plh_return_iomode = range.iomode; | ||
1524 | else if (lo->plh_return_iomode != range.iomode) | ||
1525 | lo->plh_return_iomode = IOMODE_ANY; | ||
1526 | /* | ||
1527 | * mark all matching lsegs so that we are sure to have no live | ||
1528 | * segments at hand when sending layoutreturn. See pnfs_put_lseg() | ||
1529 | * for how it works. | ||
1530 | */ | ||
1531 | pnfs_mark_matching_lsegs_return(lo, &free_me, &range); | ||
1532 | spin_unlock(&inode->i_lock); | ||
1533 | pnfs_free_lseg_list(&free_me); | ||
1534 | } | ||
1535 | EXPORT_SYMBOL_GPL(pnfs_error_mark_layout_for_return); | ||
1536 | |||
1482 | void | 1537 | void |
1483 | pnfs_generic_pg_init_read(struct nfs_pageio_descriptor *pgio, struct nfs_page *req) | 1538 | pnfs_generic_pg_init_read(struct nfs_pageio_descriptor *pgio, struct nfs_page *req) |
1484 | { | 1539 | { |
diff --git a/fs/nfs/pnfs.h b/fs/nfs/pnfs.h index 4cf0d54e14c3..bea2030eec74 100644 --- a/fs/nfs/pnfs.h +++ b/fs/nfs/pnfs.h | |||
@@ -38,6 +38,7 @@ enum { | |||
38 | NFS_LSEG_VALID = 0, /* cleared when lseg is recalled/returned */ | 38 | NFS_LSEG_VALID = 0, /* cleared when lseg is recalled/returned */ |
39 | NFS_LSEG_ROC, /* roc bit received from server */ | 39 | NFS_LSEG_ROC, /* roc bit received from server */ |
40 | NFS_LSEG_LAYOUTCOMMIT, /* layoutcommit bit set for layoutcommit */ | 40 | NFS_LSEG_LAYOUTCOMMIT, /* layoutcommit bit set for layoutcommit */ |
41 | NFS_LSEG_LAYOUTRETURN, /* layoutreturn bit set for layoutreturn */ | ||
41 | }; | 42 | }; |
42 | 43 | ||
43 | /* Individual ip address */ | 44 | /* Individual ip address */ |
@@ -184,6 +185,7 @@ struct pnfs_layout_hdr { | |||
184 | u32 plh_barrier; /* ignore lower seqids */ | 185 | u32 plh_barrier; /* ignore lower seqids */ |
185 | unsigned long plh_retry_timestamp; | 186 | unsigned long plh_retry_timestamp; |
186 | unsigned long plh_flags; | 187 | unsigned long plh_flags; |
188 | enum pnfs_iomode plh_return_iomode; | ||
187 | loff_t plh_lwb; /* last write byte for layoutcommit */ | 189 | loff_t plh_lwb; /* last write byte for layoutcommit */ |
188 | struct rpc_cred *plh_lc_cred; /* layoutcommit cred */ | 190 | struct rpc_cred *plh_lc_cred; /* layoutcommit cred */ |
189 | struct inode *plh_inode; | 191 | struct inode *plh_inode; |
@@ -274,6 +276,8 @@ void nfs4_deviceid_mark_client_invalid(struct nfs_client *clp); | |||
274 | int pnfs_read_done_resend_to_mds(struct nfs_pgio_header *); | 276 | int pnfs_read_done_resend_to_mds(struct nfs_pgio_header *); |
275 | int pnfs_write_done_resend_to_mds(struct nfs_pgio_header *); | 277 | int pnfs_write_done_resend_to_mds(struct nfs_pgio_header *); |
276 | struct nfs4_threshold *pnfs_mdsthreshold_alloc(void); | 278 | struct nfs4_threshold *pnfs_mdsthreshold_alloc(void); |
279 | void pnfs_error_mark_layout_for_return(struct inode *inode, | ||
280 | struct pnfs_layout_segment *lseg); | ||
277 | 281 | ||
278 | /* nfs4_deviceid_flags */ | 282 | /* nfs4_deviceid_flags */ |
279 | enum { | 283 | enum { |