diff options
Diffstat (limited to 'fs/nfs/pnfs.c')
-rw-r--r-- | fs/nfs/pnfs.c | 140 |
1 files changed, 140 insertions, 0 deletions
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 | } | ||