aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTrond Myklebust <Trond.Myklebust@netapp.com>2012-09-18 19:51:12 -0400
committerTrond Myklebust <Trond.Myklebust@netapp.com>2012-09-28 16:03:09 -0400
commit1dfed2737d8cfe2f2378fddfb3bed126ff5474e7 (patch)
tree865edd1618f525a66a30eac1e017a896b4f2bb8c
parent25c7533357a4c4a9311d40cc92e9648c8a7e763e (diff)
NFSv4.1: pNFS data servers may be temporarily offline
In cases where the pNFS data server is just temporarily out of service, we want to mark it as such, and then try again later. Typically that will be in cases of network connection errors etc. This patch allows us to mark the devices as being "unavailable" for such transient errors, and will make them available for retries after a 2 minute timeout period. Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
-rw-r--r--fs/nfs/nfs4filelayout.c22
-rw-r--r--fs/nfs/nfs4filelayout.h8
-rw-r--r--fs/nfs/nfs4filelayoutdev.c15
-rw-r--r--fs/nfs/pnfs.h4
-rw-r--r--fs/nfs/pnfs_dev.c27
5 files changed, 59 insertions, 17 deletions
diff --git a/fs/nfs/nfs4filelayout.c b/fs/nfs/nfs4filelayout.c
index af6ee4ad3f15..dac2162c3ac4 100644
--- a/fs/nfs/nfs4filelayout.c
+++ b/fs/nfs/nfs4filelayout.c
@@ -205,7 +205,7 @@ static int filelayout_async_handle_error(struct rpc_task *task,
205 case -EPIPE: 205 case -EPIPE:
206 dprintk("%s DS connection error %d\n", __func__, 206 dprintk("%s DS connection error %d\n", __func__,
207 task->tk_status); 207 task->tk_status);
208 filelayout_mark_devid_invalid(devid); 208 nfs4_mark_deviceid_unavailable(devid);
209 clear_bit(NFS_INO_LAYOUTCOMMIT, &NFS_I(inode)->flags); 209 clear_bit(NFS_INO_LAYOUTCOMMIT, &NFS_I(inode)->flags);
210 _pnfs_return_layout(inode); 210 _pnfs_return_layout(inode);
211 rpc_wake_up(&tbl->slot_tbl_waitq); 211 rpc_wake_up(&tbl->slot_tbl_waitq);
@@ -269,6 +269,22 @@ filelayout_set_layoutcommit(struct nfs_write_data *wdata)
269 (unsigned long) NFS_I(hdr->inode)->layout->plh_lwb); 269 (unsigned long) NFS_I(hdr->inode)->layout->plh_lwb);
270} 270}
271 271
272bool
273filelayout_test_devid_unavailable(struct nfs4_deviceid_node *node)
274{
275 return filelayout_test_devid_invalid(node) ||
276 nfs4_test_deviceid_unavailable(node);
277}
278
279static bool
280filelayout_reset_to_mds(struct pnfs_layout_segment *lseg)
281{
282 struct nfs4_deviceid_node *node = FILELAYOUT_DEVID_NODE(lseg);
283
284 return filelayout_test_layout_invalid(lseg->pls_layout) ||
285 filelayout_test_devid_unavailable(node);
286}
287
272/* 288/*
273 * Call ops for the async read/write cases 289 * Call ops for the async read/write cases
274 * In the case of dense layouts, the offset needs to be reset to its 290 * In the case of dense layouts, the offset needs to be reset to its
@@ -613,8 +629,8 @@ filelayout_check_layout(struct pnfs_layout_hdr *lo,
613 goto out; 629 goto out;
614 } else 630 } else
615 dsaddr = container_of(d, struct nfs4_file_layout_dsaddr, id_node); 631 dsaddr = container_of(d, struct nfs4_file_layout_dsaddr, id_node);
616 /* Found deviceid is being reaped */ 632 /* Found deviceid is unavailable */
617 if (test_bit(NFS_DEVICEID_INVALID, &dsaddr->id_node.flags)) 633 if (filelayout_test_devid_unavailable(&dsaddr->id_node))
618 goto out_put; 634 goto out_put;
619 635
620 fl->dsaddr = dsaddr; 636 fl->dsaddr = dsaddr;
diff --git a/fs/nfs/nfs4filelayout.h b/fs/nfs/nfs4filelayout.h
index 11053c425a61..10b0f134400b 100644
--- a/fs/nfs/nfs4filelayout.h
+++ b/fs/nfs/nfs4filelayout.h
@@ -140,12 +140,8 @@ filelayout_test_devid_invalid(struct nfs4_deviceid_node *node)
140 return test_bit(NFS_DEVICEID_INVALID, &node->flags); 140 return test_bit(NFS_DEVICEID_INVALID, &node->flags);
141} 141}
142 142
143static inline bool 143extern bool
144filelayout_reset_to_mds(struct pnfs_layout_segment *lseg) 144filelayout_test_devid_unavailable(struct nfs4_deviceid_node *node);
145{
146 return filelayout_test_devid_invalid(FILELAYOUT_DEVID_NODE(lseg)) ||
147 filelayout_test_layout_invalid(lseg->pls_layout);
148}
149 145
150extern struct nfs_fh * 146extern struct nfs_fh *
151nfs4_fl_select_ds_fh(struct pnfs_layout_segment *lseg, u32 j); 147nfs4_fl_select_ds_fh(struct pnfs_layout_segment *lseg, u32 j);
diff --git a/fs/nfs/nfs4filelayoutdev.c b/fs/nfs/nfs4filelayoutdev.c
index b85a29df20ae..3336d5eaf879 100644
--- a/fs/nfs/nfs4filelayoutdev.c
+++ b/fs/nfs/nfs4filelayoutdev.c
@@ -804,13 +804,14 @@ nfs4_fl_prepare_ds(struct pnfs_layout_segment *lseg, u32 ds_idx)
804 struct nfs4_pnfs_ds *ds = dsaddr->ds_list[ds_idx]; 804 struct nfs4_pnfs_ds *ds = dsaddr->ds_list[ds_idx];
805 struct nfs4_deviceid_node *devid = FILELAYOUT_DEVID_NODE(lseg); 805 struct nfs4_deviceid_node *devid = FILELAYOUT_DEVID_NODE(lseg);
806 806
807 if (filelayout_test_devid_invalid(devid)) 807 if (filelayout_test_devid_unavailable(devid))
808 return NULL; 808 return NULL;
809 809
810 if (ds == NULL) { 810 if (ds == NULL) {
811 printk(KERN_ERR "NFS: %s: No data server for offset index %d\n", 811 printk(KERN_ERR "NFS: %s: No data server for offset index %d\n",
812 __func__, ds_idx); 812 __func__, ds_idx);
813 goto mark_dev_invalid; 813 filelayout_mark_devid_invalid(devid);
814 return NULL;
814 } 815 }
815 816
816 if (!ds->ds_clp) { 817 if (!ds->ds_clp) {
@@ -818,14 +819,12 @@ nfs4_fl_prepare_ds(struct pnfs_layout_segment *lseg, u32 ds_idx)
818 int err; 819 int err;
819 820
820 err = nfs4_ds_connect(s, ds); 821 err = nfs4_ds_connect(s, ds);
821 if (err) 822 if (err) {
822 goto mark_dev_invalid; 823 nfs4_mark_deviceid_unavailable(devid);
824 return NULL;
825 }
823 } 826 }
824 return ds; 827 return ds;
825
826mark_dev_invalid:
827 filelayout_mark_devid_invalid(devid);
828 return NULL;
829} 828}
830 829
831module_param(dataserver_retrans, uint, 0644); 830module_param(dataserver_retrans, uint, 0644);
diff --git a/fs/nfs/pnfs.h b/fs/nfs/pnfs.h
index bc8e5001203d..9735031e1e1a 100644
--- a/fs/nfs/pnfs.h
+++ b/fs/nfs/pnfs.h
@@ -234,6 +234,7 @@ struct nfs4_threshold *pnfs_mdsthreshold_alloc(void);
234/* nfs4_deviceid_flags */ 234/* nfs4_deviceid_flags */
235enum { 235enum {
236 NFS_DEVICEID_INVALID = 0, /* set when MDS clientid recalled */ 236 NFS_DEVICEID_INVALID = 0, /* set when MDS clientid recalled */
237 NFS_DEVICEID_UNAVAILABLE, /* device temporarily unavailable */
237}; 238};
238 239
239/* pnfs_dev.c */ 240/* pnfs_dev.c */
@@ -243,6 +244,7 @@ struct nfs4_deviceid_node {
243 const struct pnfs_layoutdriver_type *ld; 244 const struct pnfs_layoutdriver_type *ld;
244 const struct nfs_client *nfs_client; 245 const struct nfs_client *nfs_client;
245 unsigned long flags; 246 unsigned long flags;
247 unsigned long timestamp_unavailable;
246 struct nfs4_deviceid deviceid; 248 struct nfs4_deviceid deviceid;
247 atomic_t ref; 249 atomic_t ref;
248}; 250};
@@ -255,6 +257,8 @@ void nfs4_init_deviceid_node(struct nfs4_deviceid_node *,
255 const struct nfs4_deviceid *); 257 const struct nfs4_deviceid *);
256struct nfs4_deviceid_node *nfs4_insert_deviceid_node(struct nfs4_deviceid_node *); 258struct nfs4_deviceid_node *nfs4_insert_deviceid_node(struct nfs4_deviceid_node *);
257bool nfs4_put_deviceid_node(struct nfs4_deviceid_node *); 259bool nfs4_put_deviceid_node(struct nfs4_deviceid_node *);
260void nfs4_mark_deviceid_unavailable(struct nfs4_deviceid_node *node);
261bool nfs4_test_deviceid_unavailable(struct nfs4_deviceid_node *node);
258void nfs4_deviceid_purge_client(const struct nfs_client *); 262void nfs4_deviceid_purge_client(const struct nfs_client *);
259 263
260static inline void 264static inline void
diff --git a/fs/nfs/pnfs_dev.c b/fs/nfs/pnfs_dev.c
index 73f701f1f4d3..d35b62e83ea6 100644
--- a/fs/nfs/pnfs_dev.c
+++ b/fs/nfs/pnfs_dev.c
@@ -40,6 +40,8 @@
40#define NFS4_DEVICE_ID_HASH_SIZE (1 << NFS4_DEVICE_ID_HASH_BITS) 40#define NFS4_DEVICE_ID_HASH_SIZE (1 << NFS4_DEVICE_ID_HASH_BITS)
41#define NFS4_DEVICE_ID_HASH_MASK (NFS4_DEVICE_ID_HASH_SIZE - 1) 41#define NFS4_DEVICE_ID_HASH_MASK (NFS4_DEVICE_ID_HASH_SIZE - 1)
42 42
43#define PNFS_DEVICE_RETRY_TIMEOUT (120*HZ)
44
43static struct hlist_head nfs4_deviceid_cache[NFS4_DEVICE_ID_HASH_SIZE]; 45static struct hlist_head nfs4_deviceid_cache[NFS4_DEVICE_ID_HASH_SIZE];
44static DEFINE_SPINLOCK(nfs4_deviceid_lock); 46static DEFINE_SPINLOCK(nfs4_deviceid_lock);
45 47
@@ -218,6 +220,30 @@ nfs4_put_deviceid_node(struct nfs4_deviceid_node *d)
218} 220}
219EXPORT_SYMBOL_GPL(nfs4_put_deviceid_node); 221EXPORT_SYMBOL_GPL(nfs4_put_deviceid_node);
220 222
223void
224nfs4_mark_deviceid_unavailable(struct nfs4_deviceid_node *node)
225{
226 node->timestamp_unavailable = jiffies;
227 set_bit(NFS_DEVICEID_UNAVAILABLE, &node->flags);
228}
229EXPORT_SYMBOL_GPL(nfs4_mark_deviceid_unavailable);
230
231bool
232nfs4_test_deviceid_unavailable(struct nfs4_deviceid_node *node)
233{
234 if (test_bit(NFS_DEVICEID_UNAVAILABLE, &node->flags)) {
235 unsigned long start, end;
236
237 end = jiffies;
238 start = end - PNFS_DEVICE_RETRY_TIMEOUT;
239 if (time_in_range(node->timestamp_unavailable, start, end))
240 return true;
241 clear_bit(NFS_DEVICEID_UNAVAILABLE, &node->flags);
242 }
243 return false;
244}
245EXPORT_SYMBOL_GPL(nfs4_test_deviceid_unavailable);
246
221static void 247static void
222_deviceid_purge_client(const struct nfs_client *clp, long hash) 248_deviceid_purge_client(const struct nfs_client *clp, long hash)
223{ 249{
@@ -276,3 +302,4 @@ nfs4_deviceid_mark_client_invalid(struct nfs_client *clp)
276 } 302 }
277 rcu_read_unlock(); 303 rcu_read_unlock();
278} 304}
305