aboutsummaryrefslogtreecommitdiffstats
path: root/fs/nfs/pnfs.c
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/pnfs.c
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/pnfs.c')
-rw-r--r--fs/nfs/pnfs.c160
1 files changed, 157 insertions, 3 deletions
diff --git a/fs/nfs/pnfs.c b/fs/nfs/pnfs.c
index c0cd954855b9..891a0c36f992 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}