extents.c revision 2179d372d9f8b5fc5c189c89bc6a565a42151b23
11da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 21da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * linux/fs/hfsplus/extents.c 31da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 41da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Copyright (C) 2001 51da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Brad Boyer (flar@allandria.com) 61da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * (C) 2003 Ardis Technologies <roman@ardistech.com> 71da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 81da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Handling of Extents both in catalog and extents overflow trees 91da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/errno.h> 121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/fs.h> 131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/pagemap.h> 141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include "hfsplus_fs.h" 161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include "hfsplus_raw.h" 171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Compare two extents keys, returns 0 on same, pos/neg for difference */ 192179d372d9f8b5fc5c189c89bc6a565a42151b23David Elliottint hfsplus_ext_cmp_key(const hfsplus_btree_key *k1, 202179d372d9f8b5fc5c189c89bc6a565a42151b23David Elliott const hfsplus_btree_key *k2) 211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds __be32 k1id, k2id; 231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds __be32 k1s, k2s; 241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds k1id = k1->ext.cnid; 261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds k2id = k2->ext.cnid; 271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (k1id != k2id) 281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return be32_to_cpu(k1id) < be32_to_cpu(k2id) ? -1 : 1; 291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (k1->ext.fork_type != k2->ext.fork_type) 311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return k1->ext.fork_type < k2->ext.fork_type ? -1 : 1; 321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds k1s = k1->ext.start_block; 341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds k2s = k2->ext.start_block; 351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (k1s == k2s) 361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return be32_to_cpu(k1s) < be32_to_cpu(k2s) ? -1 : 1; 381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void hfsplus_ext_build_key(hfsplus_btree_key *key, u32 cnid, 411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u32 block, u8 type) 421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds key->key_len = cpu_to_be16(HFSPLUS_EXT_KEYLEN - 2); 441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds key->ext.cnid = cpu_to_be32(cnid); 451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds key->ext.start_block = cpu_to_be32(block); 461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds key->ext.fork_type = type; 471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds key->ext.pad = 0; 481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic u32 hfsplus_ext_find_block(struct hfsplus_extent *ext, u32 off) 511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int i; 531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u32 count; 541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (i = 0; i < 8; ext++, i++) { 561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds count = be32_to_cpu(ext->block_count); 571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (off < count) 581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return be32_to_cpu(ext->start_block) + off; 591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds off -= count; 601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* panic? */ 621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int hfsplus_ext_block_count(struct hfsplus_extent *ext) 661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int i; 681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u32 count = 0; 691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (i = 0; i < 8; ext++, i++) 711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds count += be32_to_cpu(ext->block_count); 721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return count; 731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic u32 hfsplus_ext_lastblock(struct hfsplus_extent *ext) 761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int i; 781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ext += 7; 801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (i = 0; i < 7; ext--, i++) 811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ext->block_count) 821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return be32_to_cpu(ext->start_block) + be32_to_cpu(ext->block_count); 841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void __hfsplus_ext_write_extent(struct inode *inode, struct hfs_find_data *fd) 871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int res; 891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds hfsplus_ext_build_key(fd->search_key, inode->i_ino, HFSPLUS_I(inode).cached_start, 911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds HFSPLUS_IS_RSRC(inode) ? HFSPLUS_TYPE_RSRC : HFSPLUS_TYPE_DATA); 921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds res = hfs_brec_find(fd); 931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (HFSPLUS_I(inode).flags & HFSPLUS_FLG_EXT_NEW) { 941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (res != -ENOENT) 951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds hfs_brec_insert(fd, HFSPLUS_I(inode).cached_extents, sizeof(hfsplus_extent_rec)); 971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds HFSPLUS_I(inode).flags &= ~(HFSPLUS_FLG_EXT_DIRTY | HFSPLUS_FLG_EXT_NEW); 981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (res) 1001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 1011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds hfs_bnode_write(fd->bnode, HFSPLUS_I(inode).cached_extents, fd->entryoffset, fd->entrylength); 1021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds HFSPLUS_I(inode).flags &= ~HFSPLUS_FLG_EXT_DIRTY; 1031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid hfsplus_ext_write_extent(struct inode *inode) 1071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (HFSPLUS_I(inode).flags & HFSPLUS_FLG_EXT_DIRTY) { 1091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct hfs_find_data fd; 1101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds hfs_find_init(HFSPLUS_SB(inode->i_sb).ext_tree, &fd); 1121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds __hfsplus_ext_write_extent(inode, &fd); 1131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds hfs_find_exit(&fd); 1141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline int __hfsplus_ext_read_extent(struct hfs_find_data *fd, 1181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct hfsplus_extent *extent, 1191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u32 cnid, u32 block, u8 type) 1201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int res; 1221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds hfsplus_ext_build_key(fd->search_key, cnid, block, type); 1241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds fd->key->ext.cnid = 0; 1251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds res = hfs_brec_find(fd); 1261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (res && res != -ENOENT) 1271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return res; 1281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (fd->key->ext.cnid != fd->search_key->ext.cnid || 1291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds fd->key->ext.fork_type != fd->search_key->ext.fork_type) 1301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -ENOENT; 1311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (fd->entrylength != sizeof(hfsplus_extent_rec)) 1321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EIO; 1331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds hfs_bnode_read(fd->bnode, extent, fd->entryoffset, sizeof(hfsplus_extent_rec)); 1341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 1351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline int __hfsplus_ext_cache_extent(struct hfs_find_data *fd, struct inode *inode, u32 block) 1381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int res; 1401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (HFSPLUS_I(inode).flags & HFSPLUS_FLG_EXT_DIRTY) 1421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds __hfsplus_ext_write_extent(inode, fd); 1431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds res = __hfsplus_ext_read_extent(fd, HFSPLUS_I(inode).cached_extents, inode->i_ino, 1451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds block, HFSPLUS_IS_RSRC(inode) ? HFSPLUS_TYPE_RSRC : HFSPLUS_TYPE_DATA); 1461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!res) { 1471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds HFSPLUS_I(inode).cached_start = be32_to_cpu(fd->key->ext.start_block); 1481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds HFSPLUS_I(inode).cached_blocks = hfsplus_ext_block_count(HFSPLUS_I(inode).cached_extents); 1491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 1501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds HFSPLUS_I(inode).cached_start = HFSPLUS_I(inode).cached_blocks = 0; 1511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds HFSPLUS_I(inode).flags &= ~(HFSPLUS_FLG_EXT_DIRTY | HFSPLUS_FLG_EXT_NEW); 1521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return res; 1541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int hfsplus_ext_read_extent(struct inode *inode, u32 block) 1571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct hfs_find_data fd; 1591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int res; 1601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (block >= HFSPLUS_I(inode).cached_start && 1621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds block < HFSPLUS_I(inode).cached_start + HFSPLUS_I(inode).cached_blocks) 1631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 1641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds hfs_find_init(HFSPLUS_SB(inode->i_sb).ext_tree, &fd); 1661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds res = __hfsplus_ext_cache_extent(&fd, inode, block); 1671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds hfs_find_exit(&fd); 1681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return res; 1691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Get a block at iblock for inode, possibly allocating if create */ 1721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint hfsplus_get_block(struct inode *inode, sector_t iblock, 1731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct buffer_head *bh_result, int create) 1741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct super_block *sb; 1761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int res = -EIO; 1771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u32 ablock, dblock, mask; 1781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int shift; 1791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sb = inode->i_sb; 1811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Convert inode block to disk allocation block */ 1831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds shift = HFSPLUS_SB(sb).alloc_blksz_shift - sb->s_blocksize_bits; 1841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ablock = iblock >> HFSPLUS_SB(sb).fs_shift; 1851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (iblock >= HFSPLUS_I(inode).fs_blocks) { 1871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (iblock > HFSPLUS_I(inode).fs_blocks || !create) 1881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EIO; 1891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ablock >= HFSPLUS_I(inode).alloc_blocks) { 1901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds res = hfsplus_file_extend(inode); 1911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (res) 1921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return res; 1931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else 1951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds create = 0; 1961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ablock < HFSPLUS_I(inode).first_blocks) { 1981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dblock = hfsplus_ext_find_block(HFSPLUS_I(inode).first_extents, ablock); 1991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto done; 2001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds down(&HFSPLUS_I(inode).extents_lock); 2031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds res = hfsplus_ext_read_extent(inode, ablock); 2041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!res) { 2051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dblock = hfsplus_ext_find_block(HFSPLUS_I(inode).cached_extents, ablock - 2061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds HFSPLUS_I(inode).cached_start); 2071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 2081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds up(&HFSPLUS_I(inode).extents_lock); 2091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EIO; 2101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds up(&HFSPLUS_I(inode).extents_lock); 2121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsdone: 2141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dprint(DBG_EXTENT, "get_block(%lu): %llu - %u\n", inode->i_ino, (long long)iblock, dblock); 2151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mask = (1 << HFSPLUS_SB(sb).fs_shift) - 1; 2161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds map_bh(bh_result, sb, (dblock << HFSPLUS_SB(sb).fs_shift) + HFSPLUS_SB(sb).blockoffset + (iblock & mask)); 2171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (create) { 2181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds set_buffer_new(bh_result); 2191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds HFSPLUS_I(inode).phys_size += sb->s_blocksize; 2201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds HFSPLUS_I(inode).fs_blocks++; 2211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds inode_add_bytes(inode, sb->s_blocksize); 2221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mark_inode_dirty(inode); 2231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 2251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 2261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void hfsplus_dump_extent(struct hfsplus_extent *extent) 2281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 2291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int i; 2301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dprint(DBG_EXTENT, " "); 2321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (i = 0; i < 8; i++) 2331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dprint(DBG_EXTENT, " %u:%u", be32_to_cpu(extent[i].start_block), 2341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds be32_to_cpu(extent[i].block_count)); 2351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dprint(DBG_EXTENT, "\n"); 2361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 2371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int hfsplus_add_extent(struct hfsplus_extent *extent, u32 offset, 2391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u32 alloc_block, u32 block_count) 2401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 2411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u32 count, start; 2421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int i; 2431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds hfsplus_dump_extent(extent); 2451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (i = 0; i < 8; extent++, i++) { 2461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds count = be32_to_cpu(extent->block_count); 2471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (offset == count) { 2481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds start = be32_to_cpu(extent->start_block); 2491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (alloc_block != start + count) { 2501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (++i >= 8) 2511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -ENOSPC; 2521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds extent++; 2531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds extent->start_block = cpu_to_be32(alloc_block); 2541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else 2551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds block_count += count; 2561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds extent->block_count = cpu_to_be32(block_count); 2571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 2581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else if (offset < count) 2591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 2601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds offset -= count; 2611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* panic? */ 2631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EIO; 2641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 2651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int hfsplus_free_extents(struct super_block *sb, 2671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct hfsplus_extent *extent, 2681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u32 offset, u32 block_nr) 2691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 2701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u32 count, start; 2711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int i; 2721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds hfsplus_dump_extent(extent); 2741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (i = 0; i < 8; extent++, i++) { 2751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds count = be32_to_cpu(extent->block_count); 2761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (offset == count) 2771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto found; 2781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else if (offset < count) 2791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 2801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds offset -= count; 2811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* panic? */ 2831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EIO; 2841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsfound: 2851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (;;) { 2861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds start = be32_to_cpu(extent->start_block); 2871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (count <= block_nr) { 2881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds hfsplus_block_free(sb, start, count); 2891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds extent->block_count = 0; 2901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds extent->start_block = 0; 2911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds block_nr -= count; 2921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 2931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds count -= block_nr; 2941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds hfsplus_block_free(sb, start + count, block_nr); 2951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds extent->block_count = cpu_to_be32(count); 2961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds block_nr = 0; 2971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!block_nr || !i) 2991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 3001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds i--; 3011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds extent--; 3021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds count = be32_to_cpu(extent->block_count); 3031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 3051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint hfsplus_free_fork(struct super_block *sb, u32 cnid, struct hfsplus_fork_raw *fork, int type) 3071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 3081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct hfs_find_data fd; 3091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds hfsplus_extent_rec ext_entry; 3101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u32 total_blocks, blocks, start; 3111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int res, i; 3121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds total_blocks = be32_to_cpu(fork->total_blocks); 3141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!total_blocks) 3151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 3161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds blocks = 0; 3181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (i = 0; i < 8; i++) 3191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds blocks += be32_to_cpu(fork->extents[i].block_count); 3201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds res = hfsplus_free_extents(sb, fork->extents, blocks, blocks); 3221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (res) 3231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return res; 3241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (total_blocks == blocks) 3251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 3261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds hfs_find_init(HFSPLUS_SB(sb).ext_tree, &fd); 3281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds do { 3291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds res = __hfsplus_ext_read_extent(&fd, ext_entry, cnid, 3301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds total_blocks, type); 3311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (res) 3321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 3331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds start = be32_to_cpu(fd.key->ext.start_block); 3341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds hfsplus_free_extents(sb, ext_entry, 3351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds total_blocks - start, 3361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds total_blocks); 3371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds hfs_brec_remove(&fd); 3381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds total_blocks = start; 3391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } while (total_blocks > blocks); 3401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds hfs_find_exit(&fd); 3411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return res; 3431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 3441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint hfsplus_file_extend(struct inode *inode) 3461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 3471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct super_block *sb = inode->i_sb; 3481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u32 start, len, goal; 3491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int res; 3501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (HFSPLUS_SB(sb).alloc_file->i_size * 8 < HFSPLUS_SB(sb).total_blocks - HFSPLUS_SB(sb).free_blocks + 8) { 3521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // extend alloc file 353634725a92938b0f282b17cec0b007dca77adebd2Roman Zippel printk(KERN_ERR "hfs: extend alloc file! (%Lu,%u,%u)\n", HFSPLUS_SB(sb).alloc_file->i_size * 8, 3541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds HFSPLUS_SB(sb).total_blocks, HFSPLUS_SB(sb).free_blocks); 3551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -ENOSPC; 3561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds down(&HFSPLUS_I(inode).extents_lock); 3591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (HFSPLUS_I(inode).alloc_blocks == HFSPLUS_I(inode).first_blocks) 3601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goal = hfsplus_ext_lastblock(HFSPLUS_I(inode).first_extents); 3611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else { 3621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds res = hfsplus_ext_read_extent(inode, HFSPLUS_I(inode).alloc_blocks); 3631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (res) 3641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto out; 3651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goal = hfsplus_ext_lastblock(HFSPLUS_I(inode).cached_extents); 3661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds len = HFSPLUS_I(inode).clump_blocks; 3691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds start = hfsplus_block_allocate(sb, HFSPLUS_SB(sb).total_blocks, goal, &len); 3701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (start >= HFSPLUS_SB(sb).total_blocks) { 3711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds start = hfsplus_block_allocate(sb, goal, 0, &len); 3721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (start >= goal) { 3731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds res = -ENOSPC; 3741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto out; 3751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dprint(DBG_EXTENT, "extend %lu: %u,%u\n", inode->i_ino, start, len); 3791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (HFSPLUS_I(inode).alloc_blocks <= HFSPLUS_I(inode).first_blocks) { 3801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!HFSPLUS_I(inode).first_blocks) { 3811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dprint(DBG_EXTENT, "first extents\n"); 3821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* no extents yet */ 3831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds HFSPLUS_I(inode).first_extents[0].start_block = cpu_to_be32(start); 3841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds HFSPLUS_I(inode).first_extents[0].block_count = cpu_to_be32(len); 3851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds res = 0; 3861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 3871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* try to append to extents in inode */ 3881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds res = hfsplus_add_extent(HFSPLUS_I(inode).first_extents, 3891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds HFSPLUS_I(inode).alloc_blocks, 3901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds start, len); 3911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (res == -ENOSPC) 3921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto insert_extent; 3931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!res) { 3951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds hfsplus_dump_extent(HFSPLUS_I(inode).first_extents); 3961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds HFSPLUS_I(inode).first_blocks += len; 3971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 3991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds res = hfsplus_add_extent(HFSPLUS_I(inode).cached_extents, 4001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds HFSPLUS_I(inode).alloc_blocks - 4011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds HFSPLUS_I(inode).cached_start, 4021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds start, len); 4031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!res) { 4041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds hfsplus_dump_extent(HFSPLUS_I(inode).cached_extents); 4051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds HFSPLUS_I(inode).flags |= HFSPLUS_FLG_EXT_DIRTY; 4061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds HFSPLUS_I(inode).cached_blocks += len; 4071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else if (res == -ENOSPC) 4081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto insert_extent; 4091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 4101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsout: 4111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds up(&HFSPLUS_I(inode).extents_lock); 4121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!res) { 4131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds HFSPLUS_I(inode).alloc_blocks += len; 4141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mark_inode_dirty(inode); 4151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 4161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return res; 4171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsinsert_extent: 4191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dprint(DBG_EXTENT, "insert new extent\n"); 4201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds hfsplus_ext_write_extent(inode); 4211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds memset(HFSPLUS_I(inode).cached_extents, 0, sizeof(hfsplus_extent_rec)); 4231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds HFSPLUS_I(inode).cached_extents[0].start_block = cpu_to_be32(start); 4241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds HFSPLUS_I(inode).cached_extents[0].block_count = cpu_to_be32(len); 4251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds hfsplus_dump_extent(HFSPLUS_I(inode).cached_extents); 4261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds HFSPLUS_I(inode).flags |= HFSPLUS_FLG_EXT_DIRTY | HFSPLUS_FLG_EXT_NEW; 4271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds HFSPLUS_I(inode).cached_start = HFSPLUS_I(inode).alloc_blocks; 4281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds HFSPLUS_I(inode).cached_blocks = len; 4291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds res = 0; 4311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto out; 4321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 4331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid hfsplus_file_truncate(struct inode *inode) 4351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 4361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct super_block *sb = inode->i_sb; 4371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct hfs_find_data fd; 4381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u32 alloc_cnt, blk_cnt, start; 4391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int res; 4401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dprint(DBG_INODE, "truncate: %lu, %Lu -> %Lu\n", inode->i_ino, 4421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (long long)HFSPLUS_I(inode).phys_size, inode->i_size); 4431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (inode->i_size > HFSPLUS_I(inode).phys_size) { 4441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct address_space *mapping = inode->i_mapping; 4451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct page *page; 4461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u32 size = inode->i_size - 1; 4471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int res; 4481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds page = grab_cache_page(mapping, size >> PAGE_CACHE_SHIFT); 4501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!page) 4511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 4521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds size &= PAGE_CACHE_SIZE - 1; 4531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds size++; 4541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds res = mapping->a_ops->prepare_write(NULL, page, size, size); 4551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!res) 4561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds res = mapping->a_ops->commit_write(NULL, page, size, size); 4571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (res) 4581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds inode->i_size = HFSPLUS_I(inode).phys_size; 4591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unlock_page(page); 4601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds page_cache_release(page); 4611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mark_inode_dirty(inode); 4621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 463f76d28d235cf777dd2e1c1d48c16ee10c1d1587fRoman Zippel } else if (inode->i_size == HFSPLUS_I(inode).phys_size) 464f76d28d235cf777dd2e1c1d48c16ee10c1d1587fRoman Zippel return; 465f76d28d235cf777dd2e1c1d48c16ee10c1d1587fRoman Zippel 4661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds blk_cnt = (inode->i_size + HFSPLUS_SB(sb).alloc_blksz - 1) >> HFSPLUS_SB(sb).alloc_blksz_shift; 4671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds alloc_cnt = HFSPLUS_I(inode).alloc_blocks; 4681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (blk_cnt == alloc_cnt) 4691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto out; 4701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds down(&HFSPLUS_I(inode).extents_lock); 4721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds hfs_find_init(HFSPLUS_SB(sb).ext_tree, &fd); 4731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds while (1) { 4741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (alloc_cnt == HFSPLUS_I(inode).first_blocks) { 4751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds hfsplus_free_extents(sb, HFSPLUS_I(inode).first_extents, 4761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds alloc_cnt, alloc_cnt - blk_cnt); 4771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds hfsplus_dump_extent(HFSPLUS_I(inode).first_extents); 4781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds HFSPLUS_I(inode).first_blocks = blk_cnt; 4791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 4801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 4811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds res = __hfsplus_ext_cache_extent(&fd, inode, alloc_cnt); 4821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (res) 4831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 4841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds start = HFSPLUS_I(inode).cached_start; 4851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds hfsplus_free_extents(sb, HFSPLUS_I(inode).cached_extents, 4861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds alloc_cnt - start, alloc_cnt - blk_cnt); 4871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds hfsplus_dump_extent(HFSPLUS_I(inode).cached_extents); 4881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (blk_cnt > start) { 4891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds HFSPLUS_I(inode).flags |= HFSPLUS_FLG_EXT_DIRTY; 4901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 4911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 4921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds alloc_cnt = start; 4931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds HFSPLUS_I(inode).cached_start = HFSPLUS_I(inode).cached_blocks = 0; 4941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds HFSPLUS_I(inode).flags &= ~(HFSPLUS_FLG_EXT_DIRTY | HFSPLUS_FLG_EXT_NEW); 4951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds hfs_brec_remove(&fd); 4961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 4971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds hfs_find_exit(&fd); 4981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds up(&HFSPLUS_I(inode).extents_lock); 4991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds HFSPLUS_I(inode).alloc_blocks = blk_cnt; 5011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsout: 5021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds HFSPLUS_I(inode).phys_size = inode->i_size; 5031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds HFSPLUS_I(inode).fs_blocks = (inode->i_size + sb->s_blocksize - 1) >> sb->s_blocksize_bits; 5041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds inode_set_bytes(inode, HFSPLUS_I(inode).fs_blocks << sb->s_blocksize_bits); 5051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mark_inode_dirty(inode); 5061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 507