aboutsummaryrefslogtreecommitdiffstats
path: root/fs/nfs
diff options
context:
space:
mode:
authorFred Isaman <iisaman@citi.umich.edu>2011-07-30 20:52:45 -0400
committerTrond Myklebust <Trond.Myklebust@netapp.com>2011-07-31 12:18:16 -0400
commit03341d2cc91c700fc38883e572043a6a8f17dd5c (patch)
treeb5e25d8597188adac536b24158f51ed99e0b10f9 /fs/nfs
parenta60d2ebd93d3c5db5b6913c4844b8e6bd3b5538e (diff)
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>
Diffstat (limited to 'fs/nfs')
-rw-r--r--fs/nfs/blocklayout/blocklayout.h13
-rw-r--r--fs/nfs/blocklayout/extents.c106
2 files changed, 119 insertions, 0 deletions
diff --git a/fs/nfs/blocklayout/blocklayout.h b/fs/nfs/blocklayout/blocklayout.h
index 3e05b08d5347..581d8f47a723 100644
--- a/fs/nfs/blocklayout/blocklayout.h
+++ b/fs/nfs/blocklayout/blocklayout.h
@@ -80,6 +80,14 @@ enum extentclass4 {
80 EXTENT_LISTS = 2, 80 EXTENT_LISTS = 2,
81}; 81};
82 82
83static 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
83struct pnfs_block_layout { 91struct pnfs_block_layout {
84 struct pnfs_layout_hdr bl_layout; 92 struct pnfs_layout_hdr bl_layout;
85 struct pnfs_inval_markings bl_inval; /* tracks INVAL->RW transition */ 93 struct pnfs_inval_markings bl_inval; /* tracks INVAL->RW transition */
@@ -137,5 +145,10 @@ int nfs4_blk_process_layoutget(struct pnfs_layout_hdr *lo,
137/* blocklayoutdm.c */ 145/* blocklayoutdm.c */
138void bl_free_block_dev(struct pnfs_block_dev *bdev); 146void bl_free_block_dev(struct pnfs_block_dev *bdev);
139 147
148/* extents.c */
140void bl_put_extent(struct pnfs_block_extent *be); 149void bl_put_extent(struct pnfs_block_extent *be);
150struct pnfs_block_extent *bl_alloc_extent(void);
151int bl_add_merge_extent(struct pnfs_block_layout *bl,
152 struct pnfs_block_extent *new);
153
141#endif /* FS_NFS_NFS4BLOCKLAYOUT_H */ 154#endif /* FS_NFS_NFS4BLOCKLAYOUT_H */
diff --git a/fs/nfs/blocklayout/extents.c b/fs/nfs/blocklayout/extents.c
index d0ca7604d33e..ee4891f32492 100644
--- a/fs/nfs/blocklayout/extents.c
+++ b/fs/nfs/blocklayout/extents.c
@@ -87,3 +87,109 @@ static void print_elist(struct list_head *list)
87 } 87 }
88 dprintk("****************\n"); 88 dprintk("****************\n");
89} 89}
90
91static inline int
92extents_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 */
112int
113bl_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}