diff options
Diffstat (limited to 'fs/gfs2/bmap.c')
-rw-r--r-- | fs/gfs2/bmap.c | 108 |
1 files changed, 37 insertions, 71 deletions
diff --git a/fs/gfs2/bmap.c b/fs/gfs2/bmap.c index a25444ac648b..5a3187049dd7 100644 --- a/fs/gfs2/bmap.c +++ b/fs/gfs2/bmap.c | |||
@@ -166,7 +166,7 @@ int gfs2_unstuff_dinode(struct gfs2_inode *ip, struct page *page) | |||
166 | di->di_blocks = cpu_to_be64(ip->i_di.di_blocks); | 166 | di->di_blocks = cpu_to_be64(ip->i_di.di_blocks); |
167 | } | 167 | } |
168 | 168 | ||
169 | ip->i_di.di_height = 1; | 169 | ip->i_height = 1; |
170 | di->di_height = cpu_to_be16(1); | 170 | di->di_height = cpu_to_be16(1); |
171 | 171 | ||
172 | out_brelse: | 172 | out_brelse: |
@@ -177,43 +177,6 @@ out: | |||
177 | } | 177 | } |
178 | 178 | ||
179 | /** | 179 | /** |
180 | * calc_tree_height - Calculate the height of a metadata tree | ||
181 | * @ip: The GFS2 inode | ||
182 | * @size: The proposed size of the file | ||
183 | * | ||
184 | * Work out how tall a metadata tree needs to be in order to accommodate a | ||
185 | * file of a particular size. If size is less than the current size of | ||
186 | * the inode, then the current size of the inode is used instead of the | ||
187 | * supplied one. | ||
188 | * | ||
189 | * Returns: the height the tree should be | ||
190 | */ | ||
191 | |||
192 | static unsigned int calc_tree_height(struct gfs2_inode *ip, u64 size) | ||
193 | { | ||
194 | struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode); | ||
195 | u64 *arr; | ||
196 | unsigned int max, height; | ||
197 | |||
198 | if (ip->i_di.di_size > size) | ||
199 | size = ip->i_di.di_size; | ||
200 | |||
201 | if (gfs2_is_dir(ip)) { | ||
202 | arr = sdp->sd_jheightsize; | ||
203 | max = sdp->sd_max_jheight; | ||
204 | } else { | ||
205 | arr = sdp->sd_heightsize; | ||
206 | max = sdp->sd_max_height; | ||
207 | } | ||
208 | |||
209 | for (height = 0; height < max; height++) | ||
210 | if (arr[height] >= size) | ||
211 | break; | ||
212 | |||
213 | return height; | ||
214 | } | ||
215 | |||
216 | /** | ||
217 | * build_height - Build a metadata tree of the requested height | 180 | * build_height - Build a metadata tree of the requested height |
218 | * @ip: The GFS2 inode | 181 | * @ip: The GFS2 inode |
219 | * @height: The height to build to | 182 | * @height: The height to build to |
@@ -225,7 +188,7 @@ static unsigned int calc_tree_height(struct gfs2_inode *ip, u64 size) | |||
225 | static int build_height(struct inode *inode, unsigned height) | 188 | static int build_height(struct inode *inode, unsigned height) |
226 | { | 189 | { |
227 | struct gfs2_inode *ip = GFS2_I(inode); | 190 | struct gfs2_inode *ip = GFS2_I(inode); |
228 | unsigned new_height = height - ip->i_di.di_height; | 191 | unsigned new_height = height - ip->i_height; |
229 | struct buffer_head *dibh; | 192 | struct buffer_head *dibh; |
230 | struct buffer_head *blocks[GFS2_MAX_META_HEIGHT]; | 193 | struct buffer_head *blocks[GFS2_MAX_META_HEIGHT]; |
231 | struct gfs2_dinode *di; | 194 | struct gfs2_dinode *di; |
@@ -234,7 +197,7 @@ static int build_height(struct inode *inode, unsigned height) | |||
234 | u64 bn; | 197 | u64 bn; |
235 | unsigned n; | 198 | unsigned n; |
236 | 199 | ||
237 | if (height <= ip->i_di.di_height) | 200 | if (height <= ip->i_height) |
238 | return 0; | 201 | return 0; |
239 | 202 | ||
240 | error = gfs2_meta_inode_buffer(ip, &dibh); | 203 | error = gfs2_meta_inode_buffer(ip, &dibh); |
@@ -270,10 +233,10 @@ static int build_height(struct inode *inode, unsigned height) | |||
270 | di = (struct gfs2_dinode *)dibh->b_data; | 233 | di = (struct gfs2_dinode *)dibh->b_data; |
271 | gfs2_buffer_clear_tail(dibh, sizeof(struct gfs2_dinode)); | 234 | gfs2_buffer_clear_tail(dibh, sizeof(struct gfs2_dinode)); |
272 | *(__be64 *)(di + 1) = cpu_to_be64(bn); | 235 | *(__be64 *)(di + 1) = cpu_to_be64(bn); |
273 | ip->i_di.di_height += new_height; | 236 | ip->i_height += new_height; |
274 | ip->i_di.di_blocks += new_height; | 237 | ip->i_di.di_blocks += new_height; |
275 | gfs2_set_inode_blocks(&ip->i_inode); | 238 | gfs2_set_inode_blocks(&ip->i_inode); |
276 | di->di_height = cpu_to_be16(ip->i_di.di_height); | 239 | di->di_height = cpu_to_be16(ip->i_height); |
277 | di->di_blocks = cpu_to_be64(ip->i_di.di_blocks); | 240 | di->di_blocks = cpu_to_be64(ip->i_di.di_blocks); |
278 | brelse(dibh); | 241 | brelse(dibh); |
279 | return error; | 242 | return error; |
@@ -345,7 +308,7 @@ static void find_metapath(struct gfs2_inode *ip, u64 block, | |||
345 | u64 b = block; | 308 | u64 b = block; |
346 | unsigned int i; | 309 | unsigned int i; |
347 | 310 | ||
348 | for (i = ip->i_di.di_height; i--;) | 311 | for (i = ip->i_height; i--;) |
349 | mp->mp_list[i] = do_div(b, sdp->sd_inptrs); | 312 | mp->mp_list[i] = do_div(b, sdp->sd_inptrs); |
350 | 313 | ||
351 | } | 314 | } |
@@ -407,7 +370,7 @@ static int lookup_block(struct gfs2_inode *ip, struct buffer_head *bh, | |||
407 | if (!create) | 370 | if (!create) |
408 | return 0; | 371 | return 0; |
409 | 372 | ||
410 | if (height == ip->i_di.di_height - 1 && !gfs2_is_dir(ip)) | 373 | if (height == ip->i_height - 1 && !gfs2_is_dir(ip)) |
411 | *block = gfs2_alloc_data(ip); | 374 | *block = gfs2_alloc_data(ip); |
412 | else | 375 | else |
413 | *block = gfs2_alloc_meta(ip); | 376 | *block = gfs2_alloc_meta(ip); |
@@ -458,8 +421,7 @@ int gfs2_block_map(struct inode *inode, sector_t lblock, | |||
458 | struct gfs2_inode *ip = GFS2_I(inode); | 421 | struct gfs2_inode *ip = GFS2_I(inode); |
459 | struct gfs2_sbd *sdp = GFS2_SB(inode); | 422 | struct gfs2_sbd *sdp = GFS2_SB(inode); |
460 | struct buffer_head *bh; | 423 | struct buffer_head *bh; |
461 | unsigned int bsize; | 424 | unsigned int bsize = sdp->sd_sb.sb_bsize; |
462 | unsigned int height; | ||
463 | unsigned int end_of_metadata; | 425 | unsigned int end_of_metadata; |
464 | unsigned int x; | 426 | unsigned int x; |
465 | int error = 0; | 427 | int error = 0; |
@@ -470,7 +432,7 @@ int gfs2_block_map(struct inode *inode, sector_t lblock, | |||
470 | struct metapath mp; | 432 | struct metapath mp; |
471 | u64 size; | 433 | u64 size; |
472 | struct buffer_head *dibh = NULL; | 434 | struct buffer_head *dibh = NULL; |
473 | 435 | const u64 *arr = sdp->sd_heightsize; | |
474 | BUG_ON(maxlen == 0); | 436 | BUG_ON(maxlen == 0); |
475 | 437 | ||
476 | if (gfs2_assert_warn(sdp, !gfs2_is_stuffed(ip))) | 438 | if (gfs2_assert_warn(sdp, !gfs2_is_stuffed(ip))) |
@@ -480,23 +442,25 @@ int gfs2_block_map(struct inode *inode, sector_t lblock, | |||
480 | clear_buffer_mapped(bh_map); | 442 | clear_buffer_mapped(bh_map); |
481 | clear_buffer_new(bh_map); | 443 | clear_buffer_new(bh_map); |
482 | clear_buffer_boundary(bh_map); | 444 | clear_buffer_boundary(bh_map); |
483 | bsize = gfs2_is_dir(ip) ? sdp->sd_jbsize : sdp->sd_sb.sb_bsize; | 445 | if (gfs2_is_dir(ip)) { |
446 | bsize = sdp->sd_jbsize; | ||
447 | arr = sdp->sd_jheightsize; | ||
448 | } | ||
484 | size = (lblock + 1) * bsize; | 449 | size = (lblock + 1) * bsize; |
485 | 450 | ||
486 | if (size > ip->i_di.di_size) { | 451 | if (size > arr[ip->i_height]) { |
487 | height = calc_tree_height(ip, size); | 452 | u8 height = ip->i_height; |
488 | if (ip->i_di.di_height < height) { | 453 | if (!create) |
489 | if (!create) | 454 | goto out_ok; |
490 | goto out_ok; | 455 | while (size > arr[height]) |
491 | 456 | height++; | |
492 | error = build_height(inode, height); | 457 | error = build_height(inode, height); |
493 | if (error) | 458 | if (error) |
494 | goto out_fail; | 459 | goto out_fail; |
495 | } | ||
496 | } | 460 | } |
497 | 461 | ||
498 | find_metapath(ip, lblock, &mp); | 462 | find_metapath(ip, lblock, &mp); |
499 | end_of_metadata = ip->i_di.di_height - 1; | 463 | end_of_metadata = ip->i_height - 1; |
500 | error = gfs2_meta_inode_buffer(ip, &bh); | 464 | error = gfs2_meta_inode_buffer(ip, &bh); |
501 | if (error) | 465 | if (error) |
502 | goto out_fail; | 466 | goto out_fail; |
@@ -624,7 +588,7 @@ static int recursive_scan(struct gfs2_inode *ip, struct buffer_head *dibh, | |||
624 | if (error) | 588 | if (error) |
625 | goto out; | 589 | goto out; |
626 | 590 | ||
627 | if (height < ip->i_di.di_height - 1) | 591 | if (height < ip->i_height - 1) |
628 | for (; top < bottom; top++, first = 0) { | 592 | for (; top < bottom; top++, first = 0) { |
629 | if (!*top) | 593 | if (!*top) |
630 | continue; | 594 | continue; |
@@ -682,7 +646,7 @@ static int do_strip(struct gfs2_inode *ip, struct buffer_head *dibh, | |||
682 | sm->sm_first = 0; | 646 | sm->sm_first = 0; |
683 | } | 647 | } |
684 | 648 | ||
685 | metadata = (height != ip->i_di.di_height - 1); | 649 | metadata = (height != ip->i_height - 1); |
686 | if (metadata) | 650 | if (metadata) |
687 | revokes = (height) ? sdp->sd_inptrs : sdp->sd_diptrs; | 651 | revokes = (height) ? sdp->sd_inptrs : sdp->sd_diptrs; |
688 | 652 | ||
@@ -807,7 +771,6 @@ static int do_grow(struct gfs2_inode *ip, u64 size) | |||
807 | struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode); | 771 | struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode); |
808 | struct gfs2_alloc *al; | 772 | struct gfs2_alloc *al; |
809 | struct buffer_head *dibh; | 773 | struct buffer_head *dibh; |
810 | unsigned int h; | ||
811 | int error; | 774 | int error; |
812 | 775 | ||
813 | al = gfs2_alloc_get(ip); | 776 | al = gfs2_alloc_get(ip); |
@@ -833,20 +796,23 @@ static int do_grow(struct gfs2_inode *ip, u64 size) | |||
833 | goto out_ipres; | 796 | goto out_ipres; |
834 | 797 | ||
835 | if (size > sdp->sd_sb.sb_bsize - sizeof(struct gfs2_dinode)) { | 798 | if (size > sdp->sd_sb.sb_bsize - sizeof(struct gfs2_dinode)) { |
799 | const u64 *arr = sdp->sd_heightsize; | ||
836 | if (gfs2_is_stuffed(ip)) { | 800 | if (gfs2_is_stuffed(ip)) { |
837 | error = gfs2_unstuff_dinode(ip, NULL); | 801 | error = gfs2_unstuff_dinode(ip, NULL); |
838 | if (error) | 802 | if (error) |
839 | goto out_end_trans; | 803 | goto out_end_trans; |
840 | } | 804 | } |
841 | 805 | ||
842 | h = calc_tree_height(ip, size); | 806 | down_write(&ip->i_rw_mutex); |
843 | if (ip->i_di.di_height < h) { | 807 | if (size > arr[ip->i_height]) { |
844 | down_write(&ip->i_rw_mutex); | 808 | u8 height = ip->i_height; |
845 | error = build_height(&ip->i_inode, h); | 809 | while(size > arr[height]) |
846 | up_write(&ip->i_rw_mutex); | 810 | height++; |
847 | if (error) | 811 | error = build_height(&ip->i_inode, height); |
848 | goto out_end_trans; | ||
849 | } | 812 | } |
813 | up_write(&ip->i_rw_mutex); | ||
814 | if (error) | ||
815 | goto out_end_trans; | ||
850 | } | 816 | } |
851 | 817 | ||
852 | ip->i_di.di_size = size; | 818 | ip->i_di.di_size = size; |
@@ -989,7 +955,7 @@ out: | |||
989 | 955 | ||
990 | static int trunc_dealloc(struct gfs2_inode *ip, u64 size) | 956 | static int trunc_dealloc(struct gfs2_inode *ip, u64 size) |
991 | { | 957 | { |
992 | unsigned int height = ip->i_di.di_height; | 958 | unsigned int height = ip->i_height; |
993 | u64 lblock; | 959 | u64 lblock; |
994 | struct metapath mp; | 960 | struct metapath mp; |
995 | int error; | 961 | int error; |
@@ -1040,7 +1006,7 @@ static int trunc_end(struct gfs2_inode *ip) | |||
1040 | goto out; | 1006 | goto out; |
1041 | 1007 | ||
1042 | if (!ip->i_di.di_size) { | 1008 | if (!ip->i_di.di_size) { |
1043 | ip->i_di.di_height = 0; | 1009 | ip->i_height = 0; |
1044 | ip->i_di.di_goal_meta = | 1010 | ip->i_di.di_goal_meta = |
1045 | ip->i_di.di_goal_data = | 1011 | ip->i_di.di_goal_data = |
1046 | ip->i_no_addr; | 1012 | ip->i_no_addr; |