aboutsummaryrefslogtreecommitdiffstats
path: root/fs/nfs
diff options
context:
space:
mode:
authorAndy Adamson <andros@netapp.com>2010-10-20 00:18:02 -0400
committerTrond Myklebust <Trond.Myklebust@netapp.com>2010-10-24 18:07:10 -0400
commit974cec8ca0352eb5d281535b714cf194a606e98f (patch)
tree0e71706c3091fc785bab0be8edc5de36816685ff /fs/nfs
parente5e940170b2136ad4d5483ef293ae284b9cc8d53 (diff)
NFS: client needs to maintain list of inodes with active layouts
In particular, server reboot will invalidate all layouts. Note that in order to have an active layout, we must get a successful response from the server. To avoid adding that machinery, this patch just includes a stub that fakes up a successful return. Since the layout is never referenced for io, this is not a problem. Signed-off-by: Andy Adamson <andros@netapp.com> Signed-off-by: Benny Halevy <bhalevy@panasas.com> Signed-off-by: Dean Hildebrand <dhildebz@umich.edu> 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/client.c4
-rw-r--r--fs/nfs/nfs4state.c2
-rw-r--r--fs/nfs/pnfs.c160
-rw-r--r--fs/nfs/pnfs.h14
4 files changed, 176 insertions, 4 deletions
diff --git a/fs/nfs/client.c b/fs/nfs/client.c
index eba0bcc1bab..e55ad211dbe 100644
--- a/fs/nfs/client.c
+++ b/fs/nfs/client.c
@@ -156,7 +156,9 @@ static struct nfs_client *nfs_alloc_client(const struct nfs_client_initdata *cl_
156 cred = rpc_lookup_machine_cred(); 156 cred = rpc_lookup_machine_cred();
157 if (!IS_ERR(cred)) 157 if (!IS_ERR(cred))
158 clp->cl_machine_cred = cred; 158 clp->cl_machine_cred = cred;
159 159#if defined(CONFIG_NFS_V4_1)
160 INIT_LIST_HEAD(&clp->cl_layouts);
161#endif
160 nfs_fscache_get_client_cookie(clp); 162 nfs_fscache_get_client_cookie(clp);
161 163
162 return clp; 164 return clp;
diff --git a/fs/nfs/nfs4state.c b/fs/nfs/nfs4state.c
index e0dc06d74b6..9c81f4d6695 100644
--- a/fs/nfs/nfs4state.c
+++ b/fs/nfs/nfs4state.c
@@ -54,6 +54,7 @@
54#include "callback.h" 54#include "callback.h"
55#include "delegation.h" 55#include "delegation.h"
56#include "internal.h" 56#include "internal.h"
57#include "pnfs.h"
57 58
58#define OPENOWNER_POOL_SIZE 8 59#define OPENOWNER_POOL_SIZE 8
59 60
@@ -1475,6 +1476,7 @@ static void nfs4_state_manager(struct nfs_client *clp)
1475 } 1476 }
1476 clear_bit(NFS4CLNT_CHECK_LEASE, &clp->cl_state); 1477 clear_bit(NFS4CLNT_CHECK_LEASE, &clp->cl_state);
1477 set_bit(NFS4CLNT_RECLAIM_REBOOT, &clp->cl_state); 1478 set_bit(NFS4CLNT_RECLAIM_REBOOT, &clp->cl_state);
1479 pnfs_destroy_all_layouts(clp);
1478 } 1480 }
1479 1481
1480 if (test_and_clear_bit(NFS4CLNT_CHECK_LEASE, &clp->cl_state)) { 1482 if (test_and_clear_bit(NFS4CLNT_CHECK_LEASE, &clp->cl_state)) {
diff --git a/fs/nfs/pnfs.c b/fs/nfs/pnfs.c
index c0cd954855b..891a0c36f99 100644
--- a/fs/nfs/pnfs.c
+++ b/fs/nfs/pnfs.c
@@ -28,6 +28,7 @@
28 */ 28 */
29 29
30#include <linux/nfs_fs.h> 30#include <linux/nfs_fs.h>
31#include "internal.h"
31#include "pnfs.h" 32#include "pnfs.h"
32 33
33#define NFSDBG_FACILITY NFSDBG_PNFS 34#define NFSDBG_FACILITY NFSDBG_PNFS
@@ -183,38 +184,189 @@ put_layout_hdr_locked(struct pnfs_layout_hdr *lo)
183 lo->refcount--; 184 lo->refcount--;
184 if (!lo->refcount) { 185 if (!lo->refcount) {
185 dprintk("%s: freeing layout cache %p\n", __func__, lo); 186 dprintk("%s: freeing layout cache %p\n", __func__, lo);
187 BUG_ON(!list_empty(&lo->layouts));
186 NFS_I(lo->inode)->layout = NULL; 188 NFS_I(lo->inode)->layout = NULL;
187 kfree(lo); 189 kfree(lo);
188 } 190 }
189} 191}
190 192
193static void
194put_layout_hdr(struct inode *inode)
195{
196 spin_lock(&inode->i_lock);
197 put_layout_hdr_locked(NFS_I(inode)->layout);
198 spin_unlock(&inode->i_lock);
199}
200
201static void
202init_lseg(struct pnfs_layout_hdr *lo, struct pnfs_layout_segment *lseg)
203{
204 INIT_LIST_HEAD(&lseg->fi_list);
205 kref_init(&lseg->kref);
206 lseg->layout = lo;
207}
208
209/* Called without i_lock held, as the free_lseg call may sleep */
210static void
211destroy_lseg(struct kref *kref)
212{
213 struct pnfs_layout_segment *lseg =
214 container_of(kref, struct pnfs_layout_segment, kref);
215 struct inode *ino = lseg->layout->inode;
216
217 dprintk("--> %s\n", __func__);
218 kfree(lseg);
219 /* Matched by get_layout_hdr_locked in pnfs_insert_layout */
220 put_layout_hdr(ino);
221}
222
223static void
224put_lseg(struct pnfs_layout_segment *lseg)
225{
226 if (!lseg)
227 return;
228
229 dprintk("%s: lseg %p ref %d\n", __func__, lseg,
230 atomic_read(&lseg->kref.refcount));
231 kref_put(&lseg->kref, destroy_lseg);
232}
233
234static void
235pnfs_clear_lseg_list(struct pnfs_layout_hdr *lo, struct list_head *tmp_list)
236{
237 struct pnfs_layout_segment *lseg, *next;
238 struct nfs_client *clp;
239
240 dprintk("%s:Begin lo %p\n", __func__, lo);
241
242 assert_spin_locked(&lo->inode->i_lock);
243 list_for_each_entry_safe(lseg, next, &lo->segs, fi_list) {
244 dprintk("%s: freeing lseg %p\n", __func__, lseg);
245 list_move(&lseg->fi_list, tmp_list);
246 }
247 clp = NFS_SERVER(lo->inode)->nfs_client;
248 spin_lock(&clp->cl_lock);
249 /* List does not take a reference, so no need for put here */
250 list_del_init(&lo->layouts);
251 spin_unlock(&clp->cl_lock);
252
253 dprintk("%s:Return\n", __func__);
254}
255
256static void
257pnfs_free_lseg_list(struct list_head *tmp_list)
258{
259 struct pnfs_layout_segment *lseg;
260
261 while (!list_empty(tmp_list)) {
262 lseg = list_entry(tmp_list->next, struct pnfs_layout_segment,
263 fi_list);
264 dprintk("%s calling put_lseg on %p\n", __func__, lseg);
265 list_del(&lseg->fi_list);
266 put_lseg(lseg);
267 }
268}
269
191void 270void
192pnfs_destroy_layout(struct nfs_inode *nfsi) 271pnfs_destroy_layout(struct nfs_inode *nfsi)
193{ 272{
194 struct pnfs_layout_hdr *lo; 273 struct pnfs_layout_hdr *lo;
274 LIST_HEAD(tmp_list);
195 275
196 spin_lock(&nfsi->vfs_inode.i_lock); 276 spin_lock(&nfsi->vfs_inode.i_lock);
197 lo = nfsi->layout; 277 lo = nfsi->layout;
198 if (lo) { 278 if (lo) {
279 pnfs_clear_lseg_list(lo, &tmp_list);
199 /* Matched by refcount set to 1 in alloc_init_layout_hdr */ 280 /* Matched by refcount set to 1 in alloc_init_layout_hdr */
200 put_layout_hdr_locked(lo); 281 put_layout_hdr_locked(lo);
201 } 282 }
202 spin_unlock(&nfsi->vfs_inode.i_lock); 283 spin_unlock(&nfsi->vfs_inode.i_lock);
284 pnfs_free_lseg_list(&tmp_list);
285}
286
287/*
288 * Called by the state manger to remove all layouts established under an
289 * expired lease.
290 */
291void
292pnfs_destroy_all_layouts(struct nfs_client *clp)
293{
294 struct pnfs_layout_hdr *lo;
295 LIST_HEAD(tmp_list);
296
297 spin_lock(&clp->cl_lock);
298 list_splice_init(&clp->cl_layouts, &tmp_list);
299 spin_unlock(&clp->cl_lock);
300
301 while (!list_empty(&tmp_list)) {
302 lo = list_entry(tmp_list.next, struct pnfs_layout_hdr,
303 layouts);
304 dprintk("%s freeing layout for inode %lu\n", __func__,
305 lo->inode->i_ino);
306 pnfs_destroy_layout(NFS_I(lo->inode));
307 }
203} 308}
204 309
205/* STUB - pretend LAYOUTGET to server failed */ 310static void pnfs_insert_layout(struct pnfs_layout_hdr *lo,
311 struct pnfs_layout_segment *lseg);
312
313/* Get layout from server. */
206static struct pnfs_layout_segment * 314static struct pnfs_layout_segment *
207send_layoutget(struct pnfs_layout_hdr *lo, 315send_layoutget(struct pnfs_layout_hdr *lo,
208 struct nfs_open_context *ctx, 316 struct nfs_open_context *ctx,
209 u32 iomode) 317 u32 iomode)
210{ 318{
211 struct inode *ino = lo->inode; 319 struct inode *ino = lo->inode;
320 struct pnfs_layout_segment *lseg;
212 321
213 set_bit(lo_fail_bit(iomode), &lo->state); 322 /* Lets pretend we sent LAYOUTGET and got a response */
323 lseg = kzalloc(sizeof(*lseg), GFP_KERNEL);
324 if (!lseg) {
325 set_bit(lo_fail_bit(iomode), &lo->state);
326 spin_lock(&ino->i_lock);
327 put_layout_hdr_locked(lo);
328 spin_unlock(&ino->i_lock);
329 return NULL;
330 }
331 init_lseg(lo, lseg);
332 lseg->iomode = IOMODE_RW;
214 spin_lock(&ino->i_lock); 333 spin_lock(&ino->i_lock);
334 pnfs_insert_layout(lo, lseg);
215 put_layout_hdr_locked(lo); 335 put_layout_hdr_locked(lo);
216 spin_unlock(&ino->i_lock); 336 spin_unlock(&ino->i_lock);
217 return NULL; 337 return lseg;
338}
339
340static void
341pnfs_insert_layout(struct pnfs_layout_hdr *lo,
342 struct pnfs_layout_segment *lseg)
343{
344 dprintk("%s:Begin\n", __func__);
345
346 assert_spin_locked(&lo->inode->i_lock);
347 if (list_empty(&lo->segs)) {
348 struct nfs_client *clp = NFS_SERVER(lo->inode)->nfs_client;
349
350 spin_lock(&clp->cl_lock);
351 BUG_ON(!list_empty(&lo->layouts));
352 list_add_tail(&lo->layouts, &clp->cl_layouts);
353 spin_unlock(&clp->cl_lock);
354 }
355 get_layout_hdr_locked(lo);
356 /* STUB - add the constructed lseg if necessary */
357 if (list_empty(&lo->segs)) {
358 list_add_tail(&lseg->fi_list, &lo->segs);
359 dprintk("%s: inserted lseg %p iomode %d at tail\n",
360 __func__, lseg, lseg->iomode);
361 } else {
362 /* There is no harm for the moment in calling this
363 * with the lock held, and the call will be removed
364 * with the STUB.
365 */
366 put_lseg(lseg);
367 }
368
369 dprintk("%s:Return\n", __func__);
218} 370}
219 371
220static struct pnfs_layout_hdr * 372static struct pnfs_layout_hdr *
@@ -226,6 +378,8 @@ alloc_init_layout_hdr(struct inode *ino)
226 if (!lo) 378 if (!lo)
227 return NULL; 379 return NULL;
228 lo->refcount = 1; 380 lo->refcount = 1;
381 INIT_LIST_HEAD(&lo->layouts);
382 INIT_LIST_HEAD(&lo->segs);
229 lo->inode = ino; 383 lo->inode = ino;
230 return lo; 384 return lo;
231} 385}
diff --git a/fs/nfs/pnfs.h b/fs/nfs/pnfs.h
index 4ed1b48c71b..1c3eb02f494 100644
--- a/fs/nfs/pnfs.h
+++ b/fs/nfs/pnfs.h
@@ -30,6 +30,13 @@
30#ifndef FS_NFS_PNFS_H 30#ifndef FS_NFS_PNFS_H
31#define FS_NFS_PNFS_H 31#define FS_NFS_PNFS_H
32 32
33struct pnfs_layout_segment {
34 struct list_head fi_list;
35 u32 iomode;
36 struct kref kref;
37 struct pnfs_layout_hdr *layout;
38};
39
33#ifdef CONFIG_NFS_V4_1 40#ifdef CONFIG_NFS_V4_1
34 41
35#define LAYOUT_NFSV4_1_MODULE_PREFIX "nfs-layouttype4" 42#define LAYOUT_NFSV4_1_MODULE_PREFIX "nfs-layouttype4"
@@ -51,6 +58,8 @@ struct pnfs_layoutdriver_type {
51 58
52struct pnfs_layout_hdr { 59struct pnfs_layout_hdr {
53 unsigned long refcount; 60 unsigned long refcount;
61 struct list_head layouts; /* other client layouts */
62 struct list_head segs; /* layout segments list */
54 unsigned long state; 63 unsigned long state;
55 struct inode *inode; 64 struct inode *inode;
56}; 65};
@@ -64,6 +73,7 @@ pnfs_update_layout(struct inode *ino, struct nfs_open_context *ctx,
64void set_pnfs_layoutdriver(struct nfs_server *, u32 id); 73void set_pnfs_layoutdriver(struct nfs_server *, u32 id);
65void unset_pnfs_layoutdriver(struct nfs_server *); 74void unset_pnfs_layoutdriver(struct nfs_server *);
66void pnfs_destroy_layout(struct nfs_inode *); 75void pnfs_destroy_layout(struct nfs_inode *);
76void pnfs_destroy_all_layouts(struct nfs_client *);
67 77
68 78
69static inline int lo_fail_bit(u32 iomode) 79static inline int lo_fail_bit(u32 iomode)
@@ -80,6 +90,10 @@ static inline int pnfs_enabled_sb(struct nfs_server *nfss)
80 90
81#else /* CONFIG_NFS_V4_1 */ 91#else /* CONFIG_NFS_V4_1 */
82 92
93static inline void pnfs_destroy_all_layouts(struct nfs_client *clp)
94{
95}
96
83static inline void pnfs_destroy_layout(struct nfs_inode *nfsi) 97static inline void pnfs_destroy_layout(struct nfs_inode *nfsi)
84{ 98{
85} 99}