Commit 03341d2cc91c700fc38883e572043a6a8f17dd5c

Authored by Fred Isaman
Committed by Trond Myklebust
1 parent a60d2ebd93

pnfsblock: merge extents

Replace a stub, so that extents underlying the layouts are properly
added, merged, or ignored as necessary.

Signed-off-by: Fred Isaman <iisaman@citi.umich.edu>
[pnfsblock: delete the new node before put it]
Signed-off-by: Mingyang Guo <guomingyang@nrchpc.ac.cn>
Signed-off-by: Benny Halevy <bhalevy@panasas.com>
Signed-off-by: Peng Tao <peng_tao@emc.com>
Signed-off-by: Benny Halevy <bhalevy@tonian.com>
Signed-off-by: Jim Rees <rees@umich.edu>
Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>

Showing 2 changed files with 119 additions and 0 deletions Side-by-side Diff

fs/nfs/blocklayout/blocklayout.h
... ... @@ -80,6 +80,14 @@
80 80 EXTENT_LISTS = 2,
81 81 };
82 82  
  83 +static inline int bl_choose_list(enum exstate4 state)
  84 +{
  85 + if (state == PNFS_BLOCK_READ_DATA || state == PNFS_BLOCK_NONE_DATA)
  86 + return RO_EXTENT;
  87 + else
  88 + return RW_EXTENT;
  89 +}
  90 +
83 91 struct pnfs_block_layout {
84 92 struct pnfs_layout_hdr bl_layout;
85 93 struct pnfs_inval_markings bl_inval; /* tracks INVAL->RW transition */
86 94  
... ... @@ -137,6 +145,11 @@
137 145 /* blocklayoutdm.c */
138 146 void bl_free_block_dev(struct pnfs_block_dev *bdev);
139 147  
  148 +/* extents.c */
140 149 void bl_put_extent(struct pnfs_block_extent *be);
  150 +struct pnfs_block_extent *bl_alloc_extent(void);
  151 +int bl_add_merge_extent(struct pnfs_block_layout *bl,
  152 + struct pnfs_block_extent *new);
  153 +
141 154 #endif /* FS_NFS_NFS4BLOCKLAYOUT_H */
fs/nfs/blocklayout/extents.c
... ... @@ -87,4 +87,110 @@
87 87 }
88 88 dprintk("****************\n");
89 89 }
  90 +
  91 +static inline int
  92 +extents_consistent(struct pnfs_block_extent *old, struct pnfs_block_extent *new)
  93 +{
  94 + /* Note this assumes new->be_f_offset >= old->be_f_offset */
  95 + return (new->be_state == old->be_state) &&
  96 + ((new->be_state == PNFS_BLOCK_NONE_DATA) ||
  97 + ((new->be_v_offset - old->be_v_offset ==
  98 + new->be_f_offset - old->be_f_offset) &&
  99 + new->be_mdev == old->be_mdev));
  100 +}
  101 +
  102 +/* Adds new to appropriate list in bl, modifying new and removing existing
  103 + * extents as appropriate to deal with overlaps.
  104 + *
  105 + * See bl_find_get_extent for list constraints.
  106 + *
  107 + * Refcount on new is already set. If end up not using it, or error out,
  108 + * need to put the reference.
  109 + *
  110 + * bl->bl_ext_lock is held by caller.
  111 + */
  112 +int
  113 +bl_add_merge_extent(struct pnfs_block_layout *bl,
  114 + struct pnfs_block_extent *new)
  115 +{
  116 + struct pnfs_block_extent *be, *tmp;
  117 + sector_t end = new->be_f_offset + new->be_length;
  118 + struct list_head *list;
  119 +
  120 + dprintk("%s enter with be=%p\n", __func__, new);
  121 + print_bl_extent(new);
  122 + list = &bl->bl_extents[bl_choose_list(new->be_state)];
  123 + print_elist(list);
  124 +
  125 + /* Scan for proper place to insert, extending new to the left
  126 + * as much as possible.
  127 + */
  128 + list_for_each_entry_safe(be, tmp, list, be_node) {
  129 + if (new->be_f_offset < be->be_f_offset)
  130 + break;
  131 + if (end <= be->be_f_offset + be->be_length) {
  132 + /* new is a subset of existing be*/
  133 + if (extents_consistent(be, new)) {
  134 + dprintk("%s: new is subset, ignoring\n",
  135 + __func__);
  136 + bl_put_extent(new);
  137 + return 0;
  138 + } else
  139 + goto out_err;
  140 + } else if (new->be_f_offset <=
  141 + be->be_f_offset + be->be_length) {
  142 + /* new overlaps or abuts existing be */
  143 + if (extents_consistent(be, new)) {
  144 + /* extend new to fully replace be */
  145 + new->be_length += new->be_f_offset -
  146 + be->be_f_offset;
  147 + new->be_f_offset = be->be_f_offset;
  148 + new->be_v_offset = be->be_v_offset;
  149 + dprintk("%s: removing %p\n", __func__, be);
  150 + list_del(&be->be_node);
  151 + bl_put_extent(be);
  152 + } else if (new->be_f_offset !=
  153 + be->be_f_offset + be->be_length)
  154 + goto out_err;
  155 + }
  156 + }
  157 + /* Note that if we never hit the above break, be will not point to a
  158 + * valid extent. However, in that case &be->be_node==list.
  159 + */
  160 + list_add_tail(&new->be_node, &be->be_node);
  161 + dprintk("%s: inserting new\n", __func__);
  162 + print_elist(list);
  163 + /* Scan forward for overlaps. If we find any, extend new and
  164 + * remove the overlapped extent.
  165 + */
  166 + be = list_prepare_entry(new, list, be_node);
  167 + list_for_each_entry_safe_continue(be, tmp, list, be_node) {
  168 + if (end < be->be_f_offset)
  169 + break;
  170 + /* new overlaps or abuts existing be */
  171 + if (extents_consistent(be, new)) {
  172 + if (end < be->be_f_offset + be->be_length) {
  173 + /* extend new to fully cover be */
  174 + end = be->be_f_offset + be->be_length;
  175 + new->be_length = end - new->be_f_offset;
  176 + }
  177 + dprintk("%s: removing %p\n", __func__, be);
  178 + list_del(&be->be_node);
  179 + bl_put_extent(be);
  180 + } else if (end != be->be_f_offset) {
  181 + list_del(&new->be_node);
  182 + goto out_err;
  183 + }
  184 + }
  185 + dprintk("%s: after merging\n", __func__);
  186 + print_elist(list);
  187 + /* FIXME - The per-list consistency checks have all been done,
  188 + * should now check cross-list consistency.
  189 + */
  190 + return 0;
  191 +
  192 + out_err:
  193 + bl_put_extent(new);
  194 + return -EIO;
  195 +}