aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBenny Halevy <bhalevy@panasas.com>2010-10-20 00:18:01 -0400
committerTrond Myklebust <Trond.Myklebust@netapp.com>2010-10-24 18:07:10 -0400
commite5e940170b2136ad4d5483ef293ae284b9cc8d53 (patch)
tree1568bf55addee6a6fdc091026083426b087e68df
parent7ab672ce312133ee4a5d85b71447b2b334403681 (diff)
NFS: create and destroy inode's layout cache
At the start of the io paths, try to grab the relevant layout information. This will initiate the inode's layout cache, but stubs ensure the cache stays empty. Signed-off-by: Benny Halevy <bhalevy@panasas.com> Signed-off-by: Dean Hildebrand <dhildebz@umich.edu> Signed-off-by: Marc Eshel <eshel@almaden.ibm.com> Signed-off-by: Tao Guo <guotao@nrchpc.ac.cn> Signed-off-by: Ricardo Labiaga <ricardo.labiaga@netapp.com> Signed-off-by: Boaz Harrosh <bharrosh@panasas.com> Signed-off-by: Andy Adamson <andros@netapp.com> Signed-off-by: Fred Isaman <iisaman@netapp.com> Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
-rw-r--r--fs/nfs/file.c5
-rw-r--r--fs/nfs/inode.c3
-rw-r--r--fs/nfs/pnfs.c140
-rw-r--r--fs/nfs/pnfs.h39
-rw-r--r--fs/nfs/read.c3
-rw-r--r--include/linux/nfs_fs.h3
6 files changed, 193 insertions, 0 deletions
diff --git a/fs/nfs/file.c b/fs/nfs/file.c
index c3f2477c16c1..91d019d39122 100644
--- a/fs/nfs/file.c
+++ b/fs/nfs/file.c
@@ -36,6 +36,7 @@
36#include "internal.h" 36#include "internal.h"
37#include "iostat.h" 37#include "iostat.h"
38#include "fscache.h" 38#include "fscache.h"
39#include "pnfs.h"
39 40
40#define NFSDBG_FACILITY NFSDBG_FILE 41#define NFSDBG_FACILITY NFSDBG_FILE
41 42
@@ -386,6 +387,10 @@ static int nfs_write_begin(struct file *file, struct address_space *mapping,
386 file->f_path.dentry->d_name.name, 387 file->f_path.dentry->d_name.name,
387 mapping->host->i_ino, len, (long long) pos); 388 mapping->host->i_ino, len, (long long) pos);
388 389
390 pnfs_update_layout(mapping->host,
391 nfs_file_open_context(file),
392 IOMODE_RW);
393
389start: 394start:
390 /* 395 /*
391 * Prevent starvation issues if someone is doing a consistency 396 * Prevent starvation issues if someone is doing a consistency
diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c
index 6eec28656415..314f57164602 100644
--- a/fs/nfs/inode.c
+++ b/fs/nfs/inode.c
@@ -48,6 +48,7 @@
48#include "internal.h" 48#include "internal.h"
49#include "fscache.h" 49#include "fscache.h"
50#include "dns_resolve.h" 50#include "dns_resolve.h"
51#include "pnfs.h"
51 52
52#define NFSDBG_FACILITY NFSDBG_VFS 53#define NFSDBG_FACILITY NFSDBG_VFS
53 54
@@ -1410,6 +1411,7 @@ void nfs4_evict_inode(struct inode *inode)
1410{ 1411{
1411 truncate_inode_pages(&inode->i_data, 0); 1412 truncate_inode_pages(&inode->i_data, 0);
1412 end_writeback(inode); 1413 end_writeback(inode);
1414 pnfs_destroy_layout(NFS_I(inode));
1413 /* If we are holding a delegation, return it! */ 1415 /* If we are holding a delegation, return it! */
1414 nfs_inode_return_delegation_noreclaim(inode); 1416 nfs_inode_return_delegation_noreclaim(inode);
1415 /* First call standard NFS clear_inode() code */ 1417 /* First call standard NFS clear_inode() code */
@@ -1447,6 +1449,7 @@ static inline void nfs4_init_once(struct nfs_inode *nfsi)
1447 nfsi->delegation = NULL; 1449 nfsi->delegation = NULL;
1448 nfsi->delegation_state = 0; 1450 nfsi->delegation_state = 0;
1449 init_rwsem(&nfsi->rwsem); 1451 init_rwsem(&nfsi->rwsem);
1452 nfsi->layout = NULL;
1450#endif 1453#endif
1451} 1454}
1452 1455
diff --git a/fs/nfs/pnfs.c b/fs/nfs/pnfs.c
index cf795625610e..c0cd954855b9 100644
--- a/fs/nfs/pnfs.c
+++ b/fs/nfs/pnfs.c
@@ -166,3 +166,143 @@ pnfs_unregister_layoutdriver(struct pnfs_layoutdriver_type *ld_type)
166 spin_unlock(&pnfs_spinlock); 166 spin_unlock(&pnfs_spinlock);
167} 167}
168EXPORT_SYMBOL_GPL(pnfs_unregister_layoutdriver); 168EXPORT_SYMBOL_GPL(pnfs_unregister_layoutdriver);
169
170static void
171get_layout_hdr_locked(struct pnfs_layout_hdr *lo)
172{
173 assert_spin_locked(&lo->inode->i_lock);
174 lo->refcount++;
175}
176
177static void
178put_layout_hdr_locked(struct pnfs_layout_hdr *lo)
179{
180 assert_spin_locked(&lo->inode->i_lock);
181 BUG_ON(lo->refcount == 0);
182
183 lo->refcount--;
184 if (!lo->refcount) {
185 dprintk("%s: freeing layout cache %p\n", __func__, lo);
186 NFS_I(lo->inode)->layout = NULL;
187 kfree(lo);
188 }
189}
190
191void
192pnfs_destroy_layout(struct nfs_inode *nfsi)
193{
194 struct pnfs_layout_hdr *lo;
195
196 spin_lock(&nfsi->vfs_inode.i_lock);
197 lo = nfsi->layout;
198 if (lo) {
199 /* Matched by refcount set to 1 in alloc_init_layout_hdr */
200 put_layout_hdr_locked(lo);
201 }
202 spin_unlock(&nfsi->vfs_inode.i_lock);
203}
204
205/* STUB - pretend LAYOUTGET to server failed */
206static struct pnfs_layout_segment *
207send_layoutget(struct pnfs_layout_hdr *lo,
208 struct nfs_open_context *ctx,
209 u32 iomode)
210{
211 struct inode *ino = lo->inode;
212
213 set_bit(lo_fail_bit(iomode), &lo->state);
214 spin_lock(&ino->i_lock);
215 put_layout_hdr_locked(lo);
216 spin_unlock(&ino->i_lock);
217 return NULL;
218}
219
220static struct pnfs_layout_hdr *
221alloc_init_layout_hdr(struct inode *ino)
222{
223 struct pnfs_layout_hdr *lo;
224
225 lo = kzalloc(sizeof(struct pnfs_layout_hdr), GFP_KERNEL);
226 if (!lo)
227 return NULL;
228 lo->refcount = 1;
229 lo->inode = ino;
230 return lo;
231}
232
233static struct pnfs_layout_hdr *
234pnfs_find_alloc_layout(struct inode *ino)
235{
236 struct nfs_inode *nfsi = NFS_I(ino);
237 struct pnfs_layout_hdr *new = NULL;
238
239 dprintk("%s Begin ino=%p layout=%p\n", __func__, ino, nfsi->layout);
240
241 assert_spin_locked(&ino->i_lock);
242 if (nfsi->layout)
243 return nfsi->layout;
244
245 spin_unlock(&ino->i_lock);
246 new = alloc_init_layout_hdr(ino);
247 spin_lock(&ino->i_lock);
248
249 if (likely(nfsi->layout == NULL)) /* Won the race? */
250 nfsi->layout = new;
251 else
252 kfree(new);
253 return nfsi->layout;
254}
255
256/* STUB - LAYOUTGET never succeeds, so cache is empty */
257static struct pnfs_layout_segment *
258pnfs_has_layout(struct pnfs_layout_hdr *lo, u32 iomode)
259{
260 return NULL;
261}
262
263/*
264 * Layout segment is retreived from the server if not cached.
265 * The appropriate layout segment is referenced and returned to the caller.
266 */
267struct pnfs_layout_segment *
268pnfs_update_layout(struct inode *ino,
269 struct nfs_open_context *ctx,
270 enum pnfs_iomode iomode)
271{
272 struct nfs_inode *nfsi = NFS_I(ino);
273 struct pnfs_layout_hdr *lo;
274 struct pnfs_layout_segment *lseg = NULL;
275
276 if (!pnfs_enabled_sb(NFS_SERVER(ino)))
277 return NULL;
278 spin_lock(&ino->i_lock);
279 lo = pnfs_find_alloc_layout(ino);
280 if (lo == NULL) {
281 dprintk("%s ERROR: can't get pnfs_layout_hdr\n", __func__);
282 goto out_unlock;
283 }
284
285 /* Check to see if the layout for the given range already exists */
286 lseg = pnfs_has_layout(lo, iomode);
287 if (lseg) {
288 dprintk("%s: Using cached lseg %p for iomode %d)\n",
289 __func__, lseg, iomode);
290 goto out_unlock;
291 }
292
293 /* if LAYOUTGET already failed once we don't try again */
294 if (test_bit(lo_fail_bit(iomode), &nfsi->layout->state))
295 goto out_unlock;
296
297 get_layout_hdr_locked(lo);
298 spin_unlock(&ino->i_lock);
299
300 lseg = send_layoutget(lo, ctx, iomode);
301out:
302 dprintk("%s end, state 0x%lx lseg %p\n", __func__,
303 nfsi->layout->state, lseg);
304 return lseg;
305out_unlock:
306 spin_unlock(&ino->i_lock);
307 goto out;
308}
diff --git a/fs/nfs/pnfs.h b/fs/nfs/pnfs.h
index 61531f338576..4ed1b48c71b1 100644
--- a/fs/nfs/pnfs.h
+++ b/fs/nfs/pnfs.h
@@ -34,6 +34,11 @@
34 34
35#define LAYOUT_NFSV4_1_MODULE_PREFIX "nfs-layouttype4" 35#define LAYOUT_NFSV4_1_MODULE_PREFIX "nfs-layouttype4"
36 36
37enum {
38 NFS_LAYOUT_RO_FAILED = 0, /* get ro layout failed stop trying */
39 NFS_LAYOUT_RW_FAILED, /* get rw layout failed stop trying */
40};
41
37/* Per-layout driver specific registration structure */ 42/* Per-layout driver specific registration structure */
38struct pnfs_layoutdriver_type { 43struct pnfs_layoutdriver_type {
39 struct list_head pnfs_tblid; 44 struct list_head pnfs_tblid;
@@ -44,14 +49,48 @@ struct pnfs_layoutdriver_type {
44 int (*uninitialize_mountpoint) (struct nfs_server *); 49 int (*uninitialize_mountpoint) (struct nfs_server *);
45}; 50};
46 51
52struct pnfs_layout_hdr {
53 unsigned long refcount;
54 unsigned long state;
55 struct inode *inode;
56};
57
47extern int pnfs_register_layoutdriver(struct pnfs_layoutdriver_type *); 58extern int pnfs_register_layoutdriver(struct pnfs_layoutdriver_type *);
48extern void pnfs_unregister_layoutdriver(struct pnfs_layoutdriver_type *); 59extern void pnfs_unregister_layoutdriver(struct pnfs_layoutdriver_type *);
49 60
61struct pnfs_layout_segment *
62pnfs_update_layout(struct inode *ino, struct nfs_open_context *ctx,
63 enum pnfs_iomode access_type);
50void set_pnfs_layoutdriver(struct nfs_server *, u32 id); 64void set_pnfs_layoutdriver(struct nfs_server *, u32 id);
51void unset_pnfs_layoutdriver(struct nfs_server *); 65void unset_pnfs_layoutdriver(struct nfs_server *);
66void pnfs_destroy_layout(struct nfs_inode *);
67
68
69static inline int lo_fail_bit(u32 iomode)
70{
71 return iomode == IOMODE_RW ?
72 NFS_LAYOUT_RW_FAILED : NFS_LAYOUT_RO_FAILED;
73}
74
75/* Return true if a layout driver is being used for this mountpoint */
76static inline int pnfs_enabled_sb(struct nfs_server *nfss)
77{
78 return nfss->pnfs_curr_ld != NULL;
79}
52 80
53#else /* CONFIG_NFS_V4_1 */ 81#else /* CONFIG_NFS_V4_1 */
54 82
83static inline void pnfs_destroy_layout(struct nfs_inode *nfsi)
84{
85}
86
87static inline struct pnfs_layout_segment *
88pnfs_update_layout(struct inode *ino, struct nfs_open_context *ctx,
89 enum pnfs_iomode access_type)
90{
91 return NULL;
92}
93
55static inline void set_pnfs_layoutdriver(struct nfs_server *s, u32 id) 94static inline void set_pnfs_layoutdriver(struct nfs_server *s, u32 id)
56{ 95{
57} 96}
diff --git a/fs/nfs/read.c b/fs/nfs/read.c
index 79859c81a943..e4b62c6f5a6e 100644
--- a/fs/nfs/read.c
+++ b/fs/nfs/read.c
@@ -25,6 +25,7 @@
25#include "internal.h" 25#include "internal.h"
26#include "iostat.h" 26#include "iostat.h"
27#include "fscache.h" 27#include "fscache.h"
28#include "pnfs.h"
28 29
29#define NFSDBG_FACILITY NFSDBG_PAGECACHE 30#define NFSDBG_FACILITY NFSDBG_PAGECACHE
30 31
@@ -120,6 +121,7 @@ int nfs_readpage_async(struct nfs_open_context *ctx, struct inode *inode,
120 len = nfs_page_length(page); 121 len = nfs_page_length(page);
121 if (len == 0) 122 if (len == 0)
122 return nfs_return_empty_page(page); 123 return nfs_return_empty_page(page);
124 pnfs_update_layout(inode, ctx, IOMODE_READ);
123 new = nfs_create_request(ctx, inode, page, 0, len); 125 new = nfs_create_request(ctx, inode, page, 0, len);
124 if (IS_ERR(new)) { 126 if (IS_ERR(new)) {
125 unlock_page(page); 127 unlock_page(page);
@@ -624,6 +626,7 @@ int nfs_readpages(struct file *filp, struct address_space *mapping,
624 if (ret == 0) 626 if (ret == 0)
625 goto read_complete; /* all pages were read */ 627 goto read_complete; /* all pages were read */
626 628
629 pnfs_update_layout(inode, desc.ctx, IOMODE_READ);
627 if (rsize < PAGE_CACHE_SIZE) 630 if (rsize < PAGE_CACHE_SIZE)
628 nfs_pageio_init(&pgio, inode, nfs_pagein_multi, rsize, 0); 631 nfs_pageio_init(&pgio, inode, nfs_pagein_multi, rsize, 0);
629 else 632 else
diff --git a/include/linux/nfs_fs.h b/include/linux/nfs_fs.h
index 499872fa895c..0833bb67c831 100644
--- a/include/linux/nfs_fs.h
+++ b/include/linux/nfs_fs.h
@@ -188,6 +188,9 @@ struct nfs_inode {
188 struct nfs_delegation *delegation; 188 struct nfs_delegation *delegation;
189 fmode_t delegation_state; 189 fmode_t delegation_state;
190 struct rw_semaphore rwsem; 190 struct rw_semaphore rwsem;
191
192 /* pNFS layout information */
193 struct pnfs_layout_hdr *layout;
191#endif /* CONFIG_NFS_V4*/ 194#endif /* CONFIG_NFS_V4*/
192#ifdef CONFIG_NFS_FSCACHE 195#ifdef CONFIG_NFS_FSCACHE
193 struct fscache_cookie *fscache; 196 struct fscache_cookie *fscache;