diff options
Diffstat (limited to 'fs/nfs')
-rw-r--r-- | fs/nfs/blocklayout/blocklayout.c | 2 | ||||
-rw-r--r-- | fs/nfs/blocklayout/blocklayout.h | 12 | ||||
-rw-r--r-- | fs/nfs/blocklayout/extents.c | 176 |
3 files changed, 146 insertions, 44 deletions
diff --git a/fs/nfs/blocklayout/blocklayout.c b/fs/nfs/blocklayout/blocklayout.c index 8c29a189f09b..d096835cfd6b 100644 --- a/fs/nfs/blocklayout/blocklayout.c +++ b/fs/nfs/blocklayout/blocklayout.c | |||
@@ -155,6 +155,8 @@ static void | |||
155 | bl_encode_layoutcommit(struct pnfs_layout_hdr *lo, struct xdr_stream *xdr, | 155 | bl_encode_layoutcommit(struct pnfs_layout_hdr *lo, struct xdr_stream *xdr, |
156 | const struct nfs4_layoutcommit_args *arg) | 156 | const struct nfs4_layoutcommit_args *arg) |
157 | { | 157 | { |
158 | dprintk("%s enter\n", __func__); | ||
159 | encode_pnfs_block_layoutupdate(BLK_LO2EXT(lo), xdr, arg); | ||
158 | } | 160 | } |
159 | 161 | ||
160 | static void | 162 | static void |
diff --git a/fs/nfs/blocklayout/blocklayout.h b/fs/nfs/blocklayout/blocklayout.h index fcf47b55b5ce..3caaefce85a5 100644 --- a/fs/nfs/blocklayout/blocklayout.h +++ b/fs/nfs/blocklayout/blocklayout.h | |||
@@ -91,6 +91,15 @@ struct pnfs_block_extent { | |||
91 | struct pnfs_inval_markings *be_inval; /* tracks INVAL->RW transition */ | 91 | struct pnfs_inval_markings *be_inval; /* tracks INVAL->RW transition */ |
92 | }; | 92 | }; |
93 | 93 | ||
94 | /* Shortened extent used by LAYOUTCOMMIT */ | ||
95 | struct pnfs_block_short_extent { | ||
96 | struct list_head bse_node; | ||
97 | struct nfs4_deviceid bse_devid; | ||
98 | struct block_device *bse_mdev; | ||
99 | sector_t bse_f_offset; /* the starting offset in the file */ | ||
100 | sector_t bse_length; /* the size of the extent */ | ||
101 | }; | ||
102 | |||
94 | static inline void | 103 | static inline void |
95 | BL_INIT_INVAL_MARKS(struct pnfs_inval_markings *marks, sector_t blocksize) | 104 | BL_INIT_INVAL_MARKS(struct pnfs_inval_markings *marks, sector_t blocksize) |
96 | { | 105 | { |
@@ -184,6 +193,9 @@ int bl_mark_sectors_init(struct pnfs_inval_markings *marks, | |||
184 | void bl_put_extent(struct pnfs_block_extent *be); | 193 | void bl_put_extent(struct pnfs_block_extent *be); |
185 | struct pnfs_block_extent *bl_alloc_extent(void); | 194 | struct pnfs_block_extent *bl_alloc_extent(void); |
186 | int bl_is_sector_init(struct pnfs_inval_markings *marks, sector_t isect); | 195 | int bl_is_sector_init(struct pnfs_inval_markings *marks, sector_t isect); |
196 | int encode_pnfs_block_layoutupdate(struct pnfs_block_layout *bl, | ||
197 | struct xdr_stream *xdr, | ||
198 | const struct nfs4_layoutcommit_args *arg); | ||
187 | int bl_add_merge_extent(struct pnfs_block_layout *bl, | 199 | int bl_add_merge_extent(struct pnfs_block_layout *bl, |
188 | struct pnfs_block_extent *new); | 200 | struct pnfs_block_extent *new); |
189 | 201 | ||
diff --git a/fs/nfs/blocklayout/extents.c b/fs/nfs/blocklayout/extents.c index 292aadfd4d46..84bf24087720 100644 --- a/fs/nfs/blocklayout/extents.c +++ b/fs/nfs/blocklayout/extents.c | |||
@@ -286,6 +286,49 @@ int bl_mark_sectors_init(struct pnfs_inval_markings *marks, | |||
286 | return -ENOMEM; | 286 | return -ENOMEM; |
287 | } | 287 | } |
288 | 288 | ||
289 | /* Marks sectors in [offest, offset+length) as having been written to disk. | ||
290 | * All lengths should be block aligned. | ||
291 | */ | ||
292 | static int mark_written_sectors(struct pnfs_inval_markings *marks, | ||
293 | sector_t offset, sector_t length) | ||
294 | { | ||
295 | int status; | ||
296 | |||
297 | dprintk("%s(offset=%llu,len=%llu) enter\n", __func__, | ||
298 | (u64)offset, (u64)length); | ||
299 | spin_lock(&marks->im_lock); | ||
300 | status = _set_range(&marks->im_tree, EXTENT_WRITTEN, offset, length); | ||
301 | spin_unlock(&marks->im_lock); | ||
302 | return status; | ||
303 | } | ||
304 | |||
305 | static void print_short_extent(struct pnfs_block_short_extent *be) | ||
306 | { | ||
307 | dprintk("PRINT SHORT EXTENT extent %p\n", be); | ||
308 | if (be) { | ||
309 | dprintk(" be_f_offset %llu\n", (u64)be->bse_f_offset); | ||
310 | dprintk(" be_length %llu\n", (u64)be->bse_length); | ||
311 | } | ||
312 | } | ||
313 | |||
314 | static void print_clist(struct list_head *list, unsigned int count) | ||
315 | { | ||
316 | struct pnfs_block_short_extent *be; | ||
317 | unsigned int i = 0; | ||
318 | |||
319 | ifdebug(FACILITY) { | ||
320 | printk(KERN_DEBUG "****************\n"); | ||
321 | printk(KERN_DEBUG "Extent list looks like:\n"); | ||
322 | list_for_each_entry(be, list, bse_node) { | ||
323 | i++; | ||
324 | print_short_extent(be); | ||
325 | } | ||
326 | if (i != count) | ||
327 | printk(KERN_DEBUG "\n\nExpected %u entries\n\n\n", count); | ||
328 | printk(KERN_DEBUG "****************\n"); | ||
329 | } | ||
330 | } | ||
331 | |||
289 | static void print_bl_extent(struct pnfs_block_extent *be) | 332 | static void print_bl_extent(struct pnfs_block_extent *be) |
290 | { | 333 | { |
291 | dprintk("PRINT EXTENT extent %p\n", be); | 334 | dprintk("PRINT EXTENT extent %p\n", be); |
@@ -378,65 +421,67 @@ bl_add_merge_extent(struct pnfs_block_layout *bl, | |||
378 | /* Scan for proper place to insert, extending new to the left | 421 | /* Scan for proper place to insert, extending new to the left |
379 | * as much as possible. | 422 | * as much as possible. |
380 | */ | 423 | */ |
381 | list_for_each_entry_safe(be, tmp, list, be_node) { | 424 | list_for_each_entry_safe_reverse(be, tmp, list, be_node) { |
382 | if (new->be_f_offset < be->be_f_offset) | 425 | if (new->be_f_offset >= be->be_f_offset + be->be_length) |
383 | break; | 426 | break; |
384 | if (end <= be->be_f_offset + be->be_length) { | 427 | if (new->be_f_offset >= be->be_f_offset) { |
385 | /* new is a subset of existing be*/ | 428 | if (end <= be->be_f_offset + be->be_length) { |
429 | /* new is a subset of existing be*/ | ||
430 | if (extents_consistent(be, new)) { | ||
431 | dprintk("%s: new is subset, ignoring\n", | ||
432 | __func__); | ||
433 | bl_put_extent(new); | ||
434 | return 0; | ||
435 | } else { | ||
436 | goto out_err; | ||
437 | } | ||
438 | } else { | ||
439 | /* |<-- be -->| | ||
440 | * |<-- new -->| */ | ||
441 | if (extents_consistent(be, new)) { | ||
442 | /* extend new to fully replace be */ | ||
443 | new->be_length += new->be_f_offset - | ||
444 | be->be_f_offset; | ||
445 | new->be_f_offset = be->be_f_offset; | ||
446 | new->be_v_offset = be->be_v_offset; | ||
447 | dprintk("%s: removing %p\n", __func__, be); | ||
448 | list_del(&be->be_node); | ||
449 | bl_put_extent(be); | ||
450 | } else { | ||
451 | goto out_err; | ||
452 | } | ||
453 | } | ||
454 | } else if (end >= be->be_f_offset + be->be_length) { | ||
455 | /* new extent overlap existing be */ | ||
386 | if (extents_consistent(be, new)) { | 456 | if (extents_consistent(be, new)) { |
387 | dprintk("%s: new is subset, ignoring\n", | 457 | /* extend new to fully replace be */ |
388 | __func__); | 458 | dprintk("%s: removing %p\n", __func__, be); |
389 | bl_put_extent(new); | 459 | list_del(&be->be_node); |
390 | return 0; | 460 | bl_put_extent(be); |
391 | } else | 461 | } else { |
392 | goto out_err; | 462 | goto out_err; |
393 | } else if (new->be_f_offset <= | 463 | } |
394 | be->be_f_offset + be->be_length) { | 464 | } else if (end > be->be_f_offset) { |
395 | /* new overlaps or abuts existing be */ | 465 | /* |<-- be -->| |
396 | if (extents_consistent(be, new)) { | 466 | *|<-- new -->| */ |
467 | if (extents_consistent(new, be)) { | ||
397 | /* extend new to fully replace be */ | 468 | /* extend new to fully replace be */ |
398 | new->be_length += new->be_f_offset - | 469 | new->be_length += be->be_f_offset + be->be_length - |
399 | be->be_f_offset; | 470 | new->be_f_offset - new->be_length; |
400 | new->be_f_offset = be->be_f_offset; | ||
401 | new->be_v_offset = be->be_v_offset; | ||
402 | dprintk("%s: removing %p\n", __func__, be); | 471 | dprintk("%s: removing %p\n", __func__, be); |
403 | list_del(&be->be_node); | 472 | list_del(&be->be_node); |
404 | bl_put_extent(be); | 473 | bl_put_extent(be); |
405 | } else if (new->be_f_offset != | 474 | } else { |
406 | be->be_f_offset + be->be_length) | ||
407 | goto out_err; | 475 | goto out_err; |
476 | } | ||
408 | } | 477 | } |
409 | } | 478 | } |
410 | /* Note that if we never hit the above break, be will not point to a | 479 | /* Note that if we never hit the above break, be will not point to a |
411 | * valid extent. However, in that case &be->be_node==list. | 480 | * valid extent. However, in that case &be->be_node==list. |
412 | */ | 481 | */ |
413 | list_add_tail(&new->be_node, &be->be_node); | 482 | list_add(&new->be_node, &be->be_node); |
414 | dprintk("%s: inserting new\n", __func__); | 483 | dprintk("%s: inserting new\n", __func__); |
415 | print_elist(list); | 484 | print_elist(list); |
416 | /* Scan forward for overlaps. If we find any, extend new and | ||
417 | * remove the overlapped extent. | ||
418 | */ | ||
419 | be = list_prepare_entry(new, list, be_node); | ||
420 | list_for_each_entry_safe_continue(be, tmp, list, be_node) { | ||
421 | if (end < be->be_f_offset) | ||
422 | break; | ||
423 | /* new overlaps or abuts existing be */ | ||
424 | if (extents_consistent(be, new)) { | ||
425 | if (end < be->be_f_offset + be->be_length) { | ||
426 | /* extend new to fully cover be */ | ||
427 | end = be->be_f_offset + be->be_length; | ||
428 | new->be_length = end - new->be_f_offset; | ||
429 | } | ||
430 | dprintk("%s: removing %p\n", __func__, be); | ||
431 | list_del(&be->be_node); | ||
432 | bl_put_extent(be); | ||
433 | } else if (end != be->be_f_offset) { | ||
434 | list_del(&new->be_node); | ||
435 | goto out_err; | ||
436 | } | ||
437 | } | ||
438 | dprintk("%s: after merging\n", __func__); | ||
439 | print_elist(list); | ||
440 | /* FIXME - The per-list consistency checks have all been done, | 485 | /* FIXME - The per-list consistency checks have all been done, |
441 | * should now check cross-list consistency. | 486 | * should now check cross-list consistency. |
442 | */ | 487 | */ |
@@ -494,6 +539,49 @@ bl_find_get_extent(struct pnfs_block_layout *bl, sector_t isect, | |||
494 | return ret; | 539 | return ret; |
495 | } | 540 | } |
496 | 541 | ||
542 | int | ||
543 | encode_pnfs_block_layoutupdate(struct pnfs_block_layout *bl, | ||
544 | struct xdr_stream *xdr, | ||
545 | const struct nfs4_layoutcommit_args *arg) | ||
546 | { | ||
547 | struct pnfs_block_short_extent *lce, *save; | ||
548 | unsigned int count = 0; | ||
549 | __be32 *p, *xdr_start; | ||
550 | |||
551 | dprintk("%s enter\n", __func__); | ||
552 | /* BUG - creation of bl_commit is buggy - need to wait for | ||
553 | * entire block to be marked WRITTEN before it can be added. | ||
554 | */ | ||
555 | spin_lock(&bl->bl_ext_lock); | ||
556 | /* Want to adjust for possible truncate */ | ||
557 | /* We now want to adjust argument range */ | ||
558 | |||
559 | /* XDR encode the ranges found */ | ||
560 | xdr_start = xdr_reserve_space(xdr, 8); | ||
561 | if (!xdr_start) | ||
562 | goto out; | ||
563 | list_for_each_entry_safe(lce, save, &bl->bl_commit, bse_node) { | ||
564 | p = xdr_reserve_space(xdr, 7 * 4 + sizeof(lce->bse_devid.data)); | ||
565 | if (!p) | ||
566 | break; | ||
567 | p = xdr_encode_opaque_fixed(p, lce->bse_devid.data, NFS4_DEVICEID4_SIZE); | ||
568 | p = xdr_encode_hyper(p, lce->bse_f_offset << SECTOR_SHIFT); | ||
569 | p = xdr_encode_hyper(p, lce->bse_length << SECTOR_SHIFT); | ||
570 | p = xdr_encode_hyper(p, 0LL); | ||
571 | *p++ = cpu_to_be32(PNFS_BLOCK_READWRITE_DATA); | ||
572 | list_del(&lce->bse_node); | ||
573 | list_add_tail(&lce->bse_node, &bl->bl_committing); | ||
574 | bl->bl_count--; | ||
575 | count++; | ||
576 | } | ||
577 | xdr_start[0] = cpu_to_be32((xdr->p - xdr_start - 1) * 4); | ||
578 | xdr_start[1] = cpu_to_be32(count); | ||
579 | out: | ||
580 | spin_unlock(&bl->bl_ext_lock); | ||
581 | dprintk("%s found %i ranges\n", __func__, count); | ||
582 | return 0; | ||
583 | } | ||
584 | |||
497 | /* Helper function to set_to_rw that initialize a new extent */ | 585 | /* Helper function to set_to_rw that initialize a new extent */ |
498 | static void | 586 | static void |
499 | _prep_new_extent(struct pnfs_block_extent *new, | 587 | _prep_new_extent(struct pnfs_block_extent *new, |