Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

[GFS2] Streamline indirect pointer tree height calculation

This patch improves the calculation of the tree height in order to reduce
the number of operations which are carried out on each call to gfs2_block_map.
In the common case, we now make a single comparison, rather than calculating
the required tree height from scratch each time. Also in the case that the
tree does need some extra height, we start from the current height rather from
zero when we work out what the new height ought to be.

In addition the di_height field is moved into the inode proper and reduced
in size to a u8 since the value must be between 0 and GFS2_MAX_META_HEIGHT (10).

Signed-off-by: Steven Whitehouse <swhiteho@redhat.com>

+55 -83
+37 -71
fs/gfs2/bmap.c
··· 166 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 170 di->di_height = cpu_to_be16(1); 171 171 172 172 out_brelse: ··· 174 174 out: 175 175 up_write(&ip->i_rw_mutex); 176 176 return error; 177 - } 178 - 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 177 } 215 178 216 179 /** ··· 188 225 static int build_height(struct inode *inode, unsigned height) 189 226 { 190 227 struct gfs2_inode *ip = GFS2_I(inode); 191 - unsigned new_height = height - ip->i_di.di_height; 228 + unsigned new_height = height - ip->i_height; 192 229 struct buffer_head *dibh; 193 230 struct buffer_head *blocks[GFS2_MAX_META_HEIGHT]; 194 231 struct gfs2_dinode *di; ··· 197 234 u64 bn; 198 235 unsigned n; 199 236 200 - if (height <= ip->i_di.di_height) 237 + if (height <= ip->i_height) 201 238 return 0; 202 239 203 240 error = gfs2_meta_inode_buffer(ip, &dibh); ··· 233 270 di = (struct gfs2_dinode *)dibh->b_data; 234 271 gfs2_buffer_clear_tail(dibh, sizeof(struct gfs2_dinode)); 235 272 *(__be64 *)(di + 1) = cpu_to_be64(bn); 236 - ip->i_di.di_height += new_height; 273 + ip->i_height += new_height; 237 274 ip->i_di.di_blocks += new_height; 238 275 gfs2_set_inode_blocks(&ip->i_inode); 239 - di->di_height = cpu_to_be16(ip->i_di.di_height); 276 + di->di_height = cpu_to_be16(ip->i_height); 240 277 di->di_blocks = cpu_to_be64(ip->i_di.di_blocks); 241 278 brelse(dibh); 242 279 return error; ··· 308 345 u64 b = block; 309 346 unsigned int i; 310 347 311 - for (i = ip->i_di.di_height; i--;) 348 + for (i = ip->i_height; i--;) 312 349 mp->mp_list[i] = do_div(b, sdp->sd_inptrs); 313 350 314 351 } ··· 370 407 if (!create) 371 408 return 0; 372 409 373 - if (height == ip->i_di.di_height - 1 && !gfs2_is_dir(ip)) 410 + if (height == ip->i_height - 1 && !gfs2_is_dir(ip)) 374 411 *block = gfs2_alloc_data(ip); 375 412 else 376 413 *block = gfs2_alloc_meta(ip); ··· 421 458 struct gfs2_inode *ip = GFS2_I(inode); 422 459 struct gfs2_sbd *sdp = GFS2_SB(inode); 423 460 struct buffer_head *bh; 424 - unsigned int bsize; 425 - unsigned int height; 461 + unsigned int bsize = sdp->sd_sb.sb_bsize; 426 462 unsigned int end_of_metadata; 427 463 unsigned int x; 428 464 int error = 0; ··· 432 470 struct metapath mp; 433 471 u64 size; 434 472 struct buffer_head *dibh = NULL; 435 - 473 + const u64 *arr = sdp->sd_heightsize; 436 474 BUG_ON(maxlen == 0); 437 475 438 476 if (gfs2_assert_warn(sdp, !gfs2_is_stuffed(ip))) ··· 442 480 clear_buffer_mapped(bh_map); 443 481 clear_buffer_new(bh_map); 444 482 clear_buffer_boundary(bh_map); 445 - bsize = gfs2_is_dir(ip) ? sdp->sd_jbsize : sdp->sd_sb.sb_bsize; 483 + if (gfs2_is_dir(ip)) { 484 + bsize = sdp->sd_jbsize; 485 + arr = sdp->sd_jheightsize; 486 + } 446 487 size = (lblock + 1) * bsize; 447 488 448 - if (size > ip->i_di.di_size) { 449 - height = calc_tree_height(ip, size); 450 - if (ip->i_di.di_height < height) { 451 - if (!create) 452 - goto out_ok; 453 - 454 - error = build_height(inode, height); 455 - if (error) 456 - goto out_fail; 457 - } 489 + if (size > arr[ip->i_height]) { 490 + u8 height = ip->i_height; 491 + if (!create) 492 + goto out_ok; 493 + while (size > arr[height]) 494 + height++; 495 + error = build_height(inode, height); 496 + if (error) 497 + goto out_fail; 458 498 } 459 499 460 500 find_metapath(ip, lblock, &mp); 461 - end_of_metadata = ip->i_di.di_height - 1; 501 + end_of_metadata = ip->i_height - 1; 462 502 error = gfs2_meta_inode_buffer(ip, &bh); 463 503 if (error) 464 504 goto out_fail; ··· 588 624 if (error) 589 625 goto out; 590 626 591 - if (height < ip->i_di.di_height - 1) 627 + if (height < ip->i_height - 1) 592 628 for (; top < bottom; top++, first = 0) { 593 629 if (!*top) 594 630 continue; ··· 646 682 sm->sm_first = 0; 647 683 } 648 684 649 - metadata = (height != ip->i_di.di_height - 1); 685 + metadata = (height != ip->i_height - 1); 650 686 if (metadata) 651 687 revokes = (height) ? sdp->sd_inptrs : sdp->sd_diptrs; 652 688 ··· 771 807 struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode); 772 808 struct gfs2_alloc *al; 773 809 struct buffer_head *dibh; 774 - unsigned int h; 775 810 int error; 776 811 777 812 al = gfs2_alloc_get(ip); ··· 796 833 goto out_ipres; 797 834 798 835 if (size > sdp->sd_sb.sb_bsize - sizeof(struct gfs2_dinode)) { 836 + const u64 *arr = sdp->sd_heightsize; 799 837 if (gfs2_is_stuffed(ip)) { 800 838 error = gfs2_unstuff_dinode(ip, NULL); 801 839 if (error) 802 840 goto out_end_trans; 803 841 } 804 842 805 - h = calc_tree_height(ip, size); 806 - if (ip->i_di.di_height < h) { 807 - down_write(&ip->i_rw_mutex); 808 - error = build_height(&ip->i_inode, h); 809 - up_write(&ip->i_rw_mutex); 810 - if (error) 811 - goto out_end_trans; 843 + down_write(&ip->i_rw_mutex); 844 + if (size > arr[ip->i_height]) { 845 + u8 height = ip->i_height; 846 + while(size > arr[height]) 847 + height++; 848 + error = build_height(&ip->i_inode, height); 812 849 } 850 + up_write(&ip->i_rw_mutex); 851 + if (error) 852 + goto out_end_trans; 813 853 } 814 854 815 855 ip->i_di.di_size = size; ··· 955 989 956 990 static int trunc_dealloc(struct gfs2_inode *ip, u64 size) 957 991 { 958 - unsigned int height = ip->i_di.di_height; 992 + unsigned int height = ip->i_height; 959 993 u64 lblock; 960 994 struct metapath mp; 961 995 int error; ··· 1006 1040 goto out; 1007 1041 1008 1042 if (!ip->i_di.di_size) { 1009 - ip->i_di.di_height = 0; 1043 + ip->i_height = 0; 1010 1044 ip->i_di.di_goal_meta = 1011 1045 ip->i_di.di_goal_data = 1012 1046 ip->i_no_addr;
+3 -3
fs/gfs2/incore.h
··· 246 246 u64 di_goal_data; /* data block goal */ 247 247 u64 di_generation; /* generation number for NFS */ 248 248 u32 di_flags; /* GFS2_DIF_... */ 249 - u16 di_height; /* height of metadata */ 250 249 /* These only apply to directories */ 251 250 u16 di_depth; /* Number of bits in the table */ 252 251 u32 di_entries; /* The number of entries in the directory */ ··· 267 268 u64 i_last_rg_alloc; 268 269 269 270 struct rw_semaphore i_rw_mutex; 271 + u8 i_height; 270 272 }; 271 273 272 274 /* ··· 490 490 u32 sd_qc_per_block; 491 491 u32 sd_max_dirres; /* Max blocks needed to add a directory entry */ 492 492 u32 sd_max_height; /* Max height of a file's metadata tree */ 493 - u64 sd_heightsize[GFS2_MAX_META_HEIGHT]; 493 + u64 sd_heightsize[GFS2_MAX_META_HEIGHT + 1]; 494 494 u32 sd_max_jheight; /* Max height of journaled file's meta tree */ 495 - u64 sd_jheightsize[GFS2_MAX_META_HEIGHT]; 495 + u64 sd_jheightsize[GFS2_MAX_META_HEIGHT + 1]; 496 496 497 497 struct gfs2_args sd_args; /* Mount arguments */ 498 498 struct gfs2_tune sd_tune; /* Filesystem tuning structure */
+12 -8
fs/gfs2/inode.c
··· 248 248 { 249 249 struct gfs2_dinode_host *di = &ip->i_di; 250 250 const struct gfs2_dinode *str = buf; 251 + u16 height; 251 252 252 - if (ip->i_no_addr != be64_to_cpu(str->di_num.no_addr)) { 253 - if (gfs2_consist_inode(ip)) 254 - gfs2_dinode_print(ip); 255 - return -EIO; 256 - } 253 + if (unlikely(ip->i_no_addr != be64_to_cpu(str->di_num.no_addr))) 254 + goto corrupt; 257 255 ip->i_no_formal_ino = be64_to_cpu(str->di_num.no_formal_ino); 258 256 ip->i_inode.i_mode = be32_to_cpu(str->di_mode); 259 257 ip->i_inode.i_rdev = 0; ··· 288 290 289 291 di->di_flags = be32_to_cpu(str->di_flags); 290 292 gfs2_set_inode_flags(&ip->i_inode); 291 - di->di_height = be16_to_cpu(str->di_height); 293 + height = be16_to_cpu(str->di_height); 294 + if (unlikely(height > GFS2_MAX_META_HEIGHT)) 295 + goto corrupt; 296 + ip->i_height = (u8)height; 292 297 293 298 di->di_depth = be16_to_cpu(str->di_depth); 294 299 di->di_entries = be32_to_cpu(str->di_entries); ··· 301 300 gfs2_set_aops(&ip->i_inode); 302 301 303 302 return 0; 303 + corrupt: 304 + if (gfs2_consist_inode(ip)) 305 + gfs2_dinode_print(ip); 306 + return -EIO; 304 307 } 305 308 306 309 /** ··· 1406 1401 str->di_generation = cpu_to_be64(di->di_generation); 1407 1402 1408 1403 str->di_flags = cpu_to_be32(di->di_flags); 1409 - str->di_height = cpu_to_be16(di->di_height); 1404 + str->di_height = cpu_to_be16(ip->i_height); 1410 1405 str->di_payload_format = cpu_to_be32(S_ISDIR(ip->i_inode.i_mode) && 1411 1406 !(ip->i_di.di_flags & GFS2_DIF_EXHASH) ? 1412 1407 GFS2_FORMAT_DE : 0); ··· 1435 1430 printk(KERN_INFO " di_goal_data = %llu\n", 1436 1431 (unsigned long long)di->di_goal_data); 1437 1432 printk(KERN_INFO " di_flags = 0x%.8X\n", di->di_flags); 1438 - printk(KERN_INFO " di_height = %u\n", di->di_height); 1439 1433 printk(KERN_INFO " di_depth = %u\n", di->di_depth); 1440 1434 printk(KERN_INFO " di_entries = %u\n", di->di_entries); 1441 1435 printk(KERN_INFO " di_eattr = %llu\n",
+1 -1
fs/gfs2/inode.h
··· 12 12 13 13 static inline int gfs2_is_stuffed(const struct gfs2_inode *ip) 14 14 { 15 - return !ip->i_di.di_height; 15 + return !ip->i_height; 16 16 } 17 17 18 18 static inline int gfs2_is_jdata(const struct gfs2_inode *ip)
+2
fs/gfs2/super.c
··· 316 316 sdp->sd_heightsize[x] = space; 317 317 } 318 318 sdp->sd_max_height = x; 319 + sdp->sd_heightsize[x] = ~0; 319 320 gfs2_assert(sdp, sdp->sd_max_height <= GFS2_MAX_META_HEIGHT); 320 321 321 322 sdp->sd_jheightsize[0] = sdp->sd_sb.sb_bsize - ··· 335 334 sdp->sd_jheightsize[x] = space; 336 335 } 337 336 sdp->sd_max_jheight = x; 337 + sdp->sd_jheightsize[x] = ~0; 338 338 gfs2_assert(sdp, sdp->sd_max_jheight <= GFS2_MAX_META_HEIGHT); 339 339 340 340 return 0;