diff options
-rw-r--r-- | fs/nfs/file.c | 5 | ||||
-rw-r--r-- | fs/nfs/inode.c | 3 | ||||
-rw-r--r-- | fs/nfs/pnfs.c | 140 | ||||
-rw-r--r-- | fs/nfs/pnfs.h | 39 | ||||
-rw-r--r-- | fs/nfs/read.c | 3 | ||||
-rw-r--r-- | include/linux/nfs_fs.h | 3 |
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 | |||
389 | start: | 394 | start: |
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 | } |
168 | EXPORT_SYMBOL_GPL(pnfs_unregister_layoutdriver); | 168 | EXPORT_SYMBOL_GPL(pnfs_unregister_layoutdriver); |
169 | |||
170 | static void | ||
171 | get_layout_hdr_locked(struct pnfs_layout_hdr *lo) | ||
172 | { | ||
173 | assert_spin_locked(&lo->inode->i_lock); | ||
174 | lo->refcount++; | ||
175 | } | ||
176 | |||
177 | static void | ||
178 | put_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 | |||
191 | void | ||
192 | pnfs_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 */ | ||
206 | static struct pnfs_layout_segment * | ||
207 | send_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 | |||
220 | static struct pnfs_layout_hdr * | ||
221 | alloc_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 | |||
233 | static struct pnfs_layout_hdr * | ||
234 | pnfs_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 */ | ||
257 | static struct pnfs_layout_segment * | ||
258 | pnfs_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 | */ | ||
267 | struct pnfs_layout_segment * | ||
268 | pnfs_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); | ||
301 | out: | ||
302 | dprintk("%s end, state 0x%lx lseg %p\n", __func__, | ||
303 | nfsi->layout->state, lseg); | ||
304 | return lseg; | ||
305 | out_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 | ||
37 | enum { | ||
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 */ |
38 | struct pnfs_layoutdriver_type { | 43 | struct 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 | ||
52 | struct pnfs_layout_hdr { | ||
53 | unsigned long refcount; | ||
54 | unsigned long state; | ||
55 | struct inode *inode; | ||
56 | }; | ||
57 | |||
47 | extern int pnfs_register_layoutdriver(struct pnfs_layoutdriver_type *); | 58 | extern int pnfs_register_layoutdriver(struct pnfs_layoutdriver_type *); |
48 | extern void pnfs_unregister_layoutdriver(struct pnfs_layoutdriver_type *); | 59 | extern void pnfs_unregister_layoutdriver(struct pnfs_layoutdriver_type *); |
49 | 60 | ||
61 | struct pnfs_layout_segment * | ||
62 | pnfs_update_layout(struct inode *ino, struct nfs_open_context *ctx, | ||
63 | enum pnfs_iomode access_type); | ||
50 | void set_pnfs_layoutdriver(struct nfs_server *, u32 id); | 64 | void set_pnfs_layoutdriver(struct nfs_server *, u32 id); |
51 | void unset_pnfs_layoutdriver(struct nfs_server *); | 65 | void unset_pnfs_layoutdriver(struct nfs_server *); |
66 | void pnfs_destroy_layout(struct nfs_inode *); | ||
67 | |||
68 | |||
69 | static 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 */ | ||
76 | static 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 | ||
83 | static inline void pnfs_destroy_layout(struct nfs_inode *nfsi) | ||
84 | { | ||
85 | } | ||
86 | |||
87 | static inline struct pnfs_layout_segment * | ||
88 | pnfs_update_layout(struct inode *ino, struct nfs_open_context *ctx, | ||
89 | enum pnfs_iomode access_type) | ||
90 | { | ||
91 | return NULL; | ||
92 | } | ||
93 | |||
55 | static inline void set_pnfs_layoutdriver(struct nfs_server *s, u32 id) | 94 | static 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; |