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 86d7a475d0c4a22ce12ae1d099b76327aa1637ce07Alexey Khoroshilovstatic int __hfsplus_ext_write_extent(struct inode *inode, 872753cc281c9a0e8a0a45ee2b8110866a9fe63bddAnton Salikhmetov struct hfs_find_data *fd) 881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 896af502de224c3742936d54eee7e3690c09822934Christoph Hellwig struct hfsplus_inode_info *hip = HFSPLUS_I(inode); 901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int res; 911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 927fcc99f4f2ddb1c39abc05fbb9b32f05b03c7f8fChristoph Hellwig WARN_ON(!mutex_is_locked(&hip->extents_lock)); 937fcc99f4f2ddb1c39abc05fbb9b32f05b03c7f8fChristoph Hellwig 946af502de224c3742936d54eee7e3690c09822934Christoph Hellwig hfsplus_ext_build_key(fd->search_key, inode->i_ino, hip->cached_start, 956af502de224c3742936d54eee7e3690c09822934Christoph Hellwig HFSPLUS_IS_RSRC(inode) ? 966af502de224c3742936d54eee7e3690c09822934Christoph Hellwig HFSPLUS_TYPE_RSRC : HFSPLUS_TYPE_DATA); 976af502de224c3742936d54eee7e3690c09822934Christoph Hellwig 98324ef39a8a4f693035d63527f16100ed27310eccVyacheslav Dubeyko res = hfs_brec_find(fd, hfs_find_rec_by_key); 99b33b7921db14abcd10c30d0ccfc68e364f5ef7feChristoph Hellwig if (hip->extent_state & HFSPLUS_EXT_NEW) { 1001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (res != -ENOENT) 101d7a475d0c4a22ce12ae1d099b76327aa1637ce07Alexey Khoroshilov return res; 1026af502de224c3742936d54eee7e3690c09822934Christoph Hellwig hfs_brec_insert(fd, hip->cached_extents, 1036af502de224c3742936d54eee7e3690c09822934Christoph Hellwig sizeof(hfsplus_extent_rec)); 104b33b7921db14abcd10c30d0ccfc68e364f5ef7feChristoph Hellwig hip->extent_state &= ~(HFSPLUS_EXT_DIRTY | HFSPLUS_EXT_NEW); 1051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 1061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (res) 107d7a475d0c4a22ce12ae1d099b76327aa1637ce07Alexey Khoroshilov return res; 1086af502de224c3742936d54eee7e3690c09822934Christoph Hellwig hfs_bnode_write(fd->bnode, hip->cached_extents, 1096af502de224c3742936d54eee7e3690c09822934Christoph Hellwig fd->entryoffset, fd->entrylength); 110b33b7921db14abcd10c30d0ccfc68e364f5ef7feChristoph Hellwig hip->extent_state &= ~HFSPLUS_EXT_DIRTY; 1111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 112e34947056076ca5467ee8256d2d9cbc594a79b37Christoph Hellwig 113e34947056076ca5467ee8256d2d9cbc594a79b37Christoph Hellwig /* 114e34947056076ca5467ee8256d2d9cbc594a79b37Christoph Hellwig * We can't just use hfsplus_mark_inode_dirty here, because we 115e34947056076ca5467ee8256d2d9cbc594a79b37Christoph Hellwig * also get called from hfsplus_write_inode, which should not 116e34947056076ca5467ee8256d2d9cbc594a79b37Christoph Hellwig * redirty the inode. Instead the callers have to be careful 117e34947056076ca5467ee8256d2d9cbc594a79b37Christoph Hellwig * to explicily mark the inode dirty, too. 118e34947056076ca5467ee8256d2d9cbc594a79b37Christoph Hellwig */ 119e34947056076ca5467ee8256d2d9cbc594a79b37Christoph Hellwig set_bit(HFSPLUS_I_EXT_DIRTY, &hip->flags); 120d7a475d0c4a22ce12ae1d099b76327aa1637ce07Alexey Khoroshilov 121d7a475d0c4a22ce12ae1d099b76327aa1637ce07Alexey Khoroshilov return 0; 1221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 124dd7f3d5458e5c0eded620fe8192abe7e418fc94cAlexey Khoroshilovstatic int hfsplus_ext_write_extent_locked(struct inode *inode) 1251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 126d7a475d0c4a22ce12ae1d099b76327aa1637ce07Alexey Khoroshilov int res = 0; 127dd7f3d5458e5c0eded620fe8192abe7e418fc94cAlexey Khoroshilov 128b33b7921db14abcd10c30d0ccfc68e364f5ef7feChristoph Hellwig if (HFSPLUS_I(inode)->extent_state & HFSPLUS_EXT_DIRTY) { 1291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct hfs_find_data fd; 1301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 131dd7f3d5458e5c0eded620fe8192abe7e418fc94cAlexey Khoroshilov res = hfs_find_init(HFSPLUS_SB(inode->i_sb)->ext_tree, &fd); 132dd7f3d5458e5c0eded620fe8192abe7e418fc94cAlexey Khoroshilov if (res) 133dd7f3d5458e5c0eded620fe8192abe7e418fc94cAlexey Khoroshilov return res; 134d7a475d0c4a22ce12ae1d099b76327aa1637ce07Alexey Khoroshilov res = __hfsplus_ext_write_extent(inode, &fd); 135dd7f3d5458e5c0eded620fe8192abe7e418fc94cAlexey Khoroshilov hfs_find_exit(&fd); 1361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 137d7a475d0c4a22ce12ae1d099b76327aa1637ce07Alexey Khoroshilov return res; 1381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 140dd7f3d5458e5c0eded620fe8192abe7e418fc94cAlexey Khoroshilovint hfsplus_ext_write_extent(struct inode *inode) 1417fcc99f4f2ddb1c39abc05fbb9b32f05b03c7f8fChristoph Hellwig{ 142dd7f3d5458e5c0eded620fe8192abe7e418fc94cAlexey Khoroshilov int res; 143dd7f3d5458e5c0eded620fe8192abe7e418fc94cAlexey Khoroshilov 1447fcc99f4f2ddb1c39abc05fbb9b32f05b03c7f8fChristoph Hellwig mutex_lock(&HFSPLUS_I(inode)->extents_lock); 145dd7f3d5458e5c0eded620fe8192abe7e418fc94cAlexey Khoroshilov res = hfsplus_ext_write_extent_locked(inode); 1467fcc99f4f2ddb1c39abc05fbb9b32f05b03c7f8fChristoph Hellwig mutex_unlock(&HFSPLUS_I(inode)->extents_lock); 147dd7f3d5458e5c0eded620fe8192abe7e418fc94cAlexey Khoroshilov 148dd7f3d5458e5c0eded620fe8192abe7e418fc94cAlexey Khoroshilov return res; 1497fcc99f4f2ddb1c39abc05fbb9b32f05b03c7f8fChristoph Hellwig} 1507fcc99f4f2ddb1c39abc05fbb9b32f05b03c7f8fChristoph Hellwig 1511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline int __hfsplus_ext_read_extent(struct hfs_find_data *fd, 1521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct hfsplus_extent *extent, 1531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u32 cnid, u32 block, u8 type) 1541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int res; 1561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds hfsplus_ext_build_key(fd->search_key, cnid, block, type); 1581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds fd->key->ext.cnid = 0; 159324ef39a8a4f693035d63527f16100ed27310eccVyacheslav Dubeyko res = hfs_brec_find(fd, hfs_find_rec_by_key); 1601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (res && res != -ENOENT) 1611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return res; 1621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (fd->key->ext.cnid != fd->search_key->ext.cnid || 1631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds fd->key->ext.fork_type != fd->search_key->ext.fork_type) 1641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -ENOENT; 1651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (fd->entrylength != sizeof(hfsplus_extent_rec)) 1661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EIO; 1672753cc281c9a0e8a0a45ee2b8110866a9fe63bddAnton Salikhmetov hfs_bnode_read(fd->bnode, extent, fd->entryoffset, 1682753cc281c9a0e8a0a45ee2b8110866a9fe63bddAnton Salikhmetov sizeof(hfsplus_extent_rec)); 1691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 1701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1722753cc281c9a0e8a0a45ee2b8110866a9fe63bddAnton Salikhmetovstatic inline int __hfsplus_ext_cache_extent(struct hfs_find_data *fd, 1732753cc281c9a0e8a0a45ee2b8110866a9fe63bddAnton Salikhmetov struct inode *inode, u32 block) 1741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1756af502de224c3742936d54eee7e3690c09822934Christoph Hellwig struct hfsplus_inode_info *hip = HFSPLUS_I(inode); 1761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int res; 1771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1787fcc99f4f2ddb1c39abc05fbb9b32f05b03c7f8fChristoph Hellwig WARN_ON(!mutex_is_locked(&hip->extents_lock)); 1797fcc99f4f2ddb1c39abc05fbb9b32f05b03c7f8fChristoph Hellwig 180d7a475d0c4a22ce12ae1d099b76327aa1637ce07Alexey Khoroshilov if (hip->extent_state & HFSPLUS_EXT_DIRTY) { 181d7a475d0c4a22ce12ae1d099b76327aa1637ce07Alexey Khoroshilov res = __hfsplus_ext_write_extent(inode, fd); 182d7a475d0c4a22ce12ae1d099b76327aa1637ce07Alexey Khoroshilov if (res) 183d7a475d0c4a22ce12ae1d099b76327aa1637ce07Alexey Khoroshilov return res; 184d7a475d0c4a22ce12ae1d099b76327aa1637ce07Alexey Khoroshilov } 1851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1866af502de224c3742936d54eee7e3690c09822934Christoph Hellwig res = __hfsplus_ext_read_extent(fd, hip->cached_extents, inode->i_ino, 1876af502de224c3742936d54eee7e3690c09822934Christoph Hellwig block, HFSPLUS_IS_RSRC(inode) ? 1886af502de224c3742936d54eee7e3690c09822934Christoph Hellwig HFSPLUS_TYPE_RSRC : 1896af502de224c3742936d54eee7e3690c09822934Christoph Hellwig HFSPLUS_TYPE_DATA); 1901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!res) { 1916af502de224c3742936d54eee7e3690c09822934Christoph Hellwig hip->cached_start = be32_to_cpu(fd->key->ext.start_block); 1922753cc281c9a0e8a0a45ee2b8110866a9fe63bddAnton Salikhmetov hip->cached_blocks = 1932753cc281c9a0e8a0a45ee2b8110866a9fe63bddAnton Salikhmetov hfsplus_ext_block_count(hip->cached_extents); 1941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 1956af502de224c3742936d54eee7e3690c09822934Christoph Hellwig hip->cached_start = hip->cached_blocks = 0; 196b33b7921db14abcd10c30d0ccfc68e364f5ef7feChristoph Hellwig hip->extent_state &= ~(HFSPLUS_EXT_DIRTY | HFSPLUS_EXT_NEW); 1971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return res; 1991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 2001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int hfsplus_ext_read_extent(struct inode *inode, u32 block) 2021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 2036af502de224c3742936d54eee7e3690c09822934Christoph Hellwig struct hfsplus_inode_info *hip = HFSPLUS_I(inode); 2041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct hfs_find_data fd; 2051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int res; 2061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2076af502de224c3742936d54eee7e3690c09822934Christoph Hellwig if (block >= hip->cached_start && 2086af502de224c3742936d54eee7e3690c09822934Christoph Hellwig block < hip->cached_start + hip->cached_blocks) 2091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 2101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2115bd9d99d107c56ff7b35a29e930d85f91a07b2fdAlexey Khoroshilov res = hfs_find_init(HFSPLUS_SB(inode->i_sb)->ext_tree, &fd); 2125bd9d99d107c56ff7b35a29e930d85f91a07b2fdAlexey Khoroshilov if (!res) { 2135bd9d99d107c56ff7b35a29e930d85f91a07b2fdAlexey Khoroshilov res = __hfsplus_ext_cache_extent(&fd, inode, block); 2145bd9d99d107c56ff7b35a29e930d85f91a07b2fdAlexey Khoroshilov hfs_find_exit(&fd); 2155bd9d99d107c56ff7b35a29e930d85f91a07b2fdAlexey Khoroshilov } 2161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return res; 2171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 2181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Get a block at iblock for inode, possibly allocating if create */ 2201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint hfsplus_get_block(struct inode *inode, sector_t iblock, 2211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct buffer_head *bh_result, int create) 2221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 223dd73a01a30d729e8fa6f829c4582650e258e36f9Christoph Hellwig struct super_block *sb = inode->i_sb; 224dd73a01a30d729e8fa6f829c4582650e258e36f9Christoph Hellwig struct hfsplus_sb_info *sbi = HFSPLUS_SB(sb); 2256af502de224c3742936d54eee7e3690c09822934Christoph Hellwig struct hfsplus_inode_info *hip = HFSPLUS_I(inode); 2261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int res = -EIO; 2271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u32 ablock, dblock, mask; 228bf1a1b31fa3ea24e3a90821d69a5c3da066f7d6cChristoph Hellwig sector_t sector; 229e34947056076ca5467ee8256d2d9cbc594a79b37Christoph Hellwig int was_dirty = 0; 2301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Convert inode block to disk allocation block */ 232dd73a01a30d729e8fa6f829c4582650e258e36f9Christoph Hellwig ablock = iblock >> sbi->fs_shift; 2331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2346af502de224c3742936d54eee7e3690c09822934Christoph Hellwig if (iblock >= hip->fs_blocks) { 2356af502de224c3742936d54eee7e3690c09822934Christoph Hellwig if (iblock > hip->fs_blocks || !create) 2361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EIO; 2376af502de224c3742936d54eee7e3690c09822934Christoph Hellwig if (ablock >= hip->alloc_blocks) { 2382cd282a1bc6b9d111b8beee63bea0af735a8a1aaSergei Antonov res = hfsplus_file_extend(inode, false); 2391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (res) 2401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return res; 2411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else 2431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds create = 0; 2441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2456af502de224c3742936d54eee7e3690c09822934Christoph Hellwig if (ablock < hip->first_blocks) { 2466af502de224c3742936d54eee7e3690c09822934Christoph Hellwig dblock = hfsplus_ext_find_block(hip->first_extents, ablock); 2471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto done; 2481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 250248736c2a57206388c86f8cdd3392ee986e84f9fEric Sesterhenn if (inode->i_ino == HFSPLUS_EXT_CNID) 251248736c2a57206388c86f8cdd3392ee986e84f9fEric Sesterhenn return -EIO; 252248736c2a57206388c86f8cdd3392ee986e84f9fEric Sesterhenn 2536af502de224c3742936d54eee7e3690c09822934Christoph Hellwig mutex_lock(&hip->extents_lock); 254e34947056076ca5467ee8256d2d9cbc594a79b37Christoph Hellwig 255e34947056076ca5467ee8256d2d9cbc594a79b37Christoph Hellwig /* 256e34947056076ca5467ee8256d2d9cbc594a79b37Christoph Hellwig * hfsplus_ext_read_extent will write out a cached extent into 257e34947056076ca5467ee8256d2d9cbc594a79b37Christoph Hellwig * the extents btree. In that case we may have to mark the inode 258e34947056076ca5467ee8256d2d9cbc594a79b37Christoph Hellwig * dirty even for a pure read of an extent here. 259e34947056076ca5467ee8256d2d9cbc594a79b37Christoph Hellwig */ 260e34947056076ca5467ee8256d2d9cbc594a79b37Christoph Hellwig was_dirty = (hip->extent_state & HFSPLUS_EXT_DIRTY); 2611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds res = hfsplus_ext_read_extent(inode, ablock); 262e34947056076ca5467ee8256d2d9cbc594a79b37Christoph Hellwig if (res) { 2636af502de224c3742936d54eee7e3690c09822934Christoph Hellwig mutex_unlock(&hip->extents_lock); 2641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EIO; 2651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 266e34947056076ca5467ee8256d2d9cbc594a79b37Christoph Hellwig dblock = hfsplus_ext_find_block(hip->cached_extents, 267e34947056076ca5467ee8256d2d9cbc594a79b37Christoph Hellwig ablock - hip->cached_start); 2686af502de224c3742936d54eee7e3690c09822934Christoph Hellwig mutex_unlock(&hip->extents_lock); 2691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsdone: 271c2b3e1f76e5c90215bc7f740b376c0220eb8a8e3Joe Perches hfs_dbg(EXTENT, "get_block(%lu): %llu - %u\n", 2722753cc281c9a0e8a0a45ee2b8110866a9fe63bddAnton Salikhmetov inode->i_ino, (long long)iblock, dblock); 273bf1a1b31fa3ea24e3a90821d69a5c3da066f7d6cChristoph Hellwig 274dd73a01a30d729e8fa6f829c4582650e258e36f9Christoph Hellwig mask = (1 << sbi->fs_shift) - 1; 275bf1a1b31fa3ea24e3a90821d69a5c3da066f7d6cChristoph Hellwig sector = ((sector_t)dblock << sbi->fs_shift) + 276bf1a1b31fa3ea24e3a90821d69a5c3da066f7d6cChristoph Hellwig sbi->blockoffset + (iblock & mask); 277bf1a1b31fa3ea24e3a90821d69a5c3da066f7d6cChristoph Hellwig map_bh(bh_result, sb, sector); 278bf1a1b31fa3ea24e3a90821d69a5c3da066f7d6cChristoph Hellwig 2791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (create) { 2801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds set_buffer_new(bh_result); 2816af502de224c3742936d54eee7e3690c09822934Christoph Hellwig hip->phys_size += sb->s_blocksize; 2826af502de224c3742936d54eee7e3690c09822934Christoph Hellwig hip->fs_blocks++; 2831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds inode_add_bytes(inode, sb->s_blocksize); 2841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 285e34947056076ca5467ee8256d2d9cbc594a79b37Christoph Hellwig if (create || was_dirty) 286e34947056076ca5467ee8256d2d9cbc594a79b37Christoph Hellwig mark_inode_dirty(inode); 2871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 2881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 2891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void hfsplus_dump_extent(struct hfsplus_extent *extent) 2911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 2921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int i; 2931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 294c2b3e1f76e5c90215bc7f740b376c0220eb8a8e3Joe Perches hfs_dbg(EXTENT, " "); 2951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (i = 0; i < 8; i++) 296c2b3e1f76e5c90215bc7f740b376c0220eb8a8e3Joe Perches hfs_dbg_cont(EXTENT, " %u:%u", 297c2b3e1f76e5c90215bc7f740b376c0220eb8a8e3Joe Perches be32_to_cpu(extent[i].start_block), 298c2b3e1f76e5c90215bc7f740b376c0220eb8a8e3Joe Perches be32_to_cpu(extent[i].block_count)); 299c2b3e1f76e5c90215bc7f740b376c0220eb8a8e3Joe Perches hfs_dbg_cont(EXTENT, "\n"); 3001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 3011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int hfsplus_add_extent(struct hfsplus_extent *extent, u32 offset, 3031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u32 alloc_block, u32 block_count) 3041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 3051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u32 count, start; 3061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int i; 3071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds hfsplus_dump_extent(extent); 3091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (i = 0; i < 8; extent++, i++) { 3101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds count = be32_to_cpu(extent->block_count); 3111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (offset == count) { 3121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds start = be32_to_cpu(extent->start_block); 3131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (alloc_block != start + count) { 3141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (++i >= 8) 3151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -ENOSPC; 3161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds extent++; 3171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds extent->start_block = cpu_to_be32(alloc_block); 3181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else 3191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds block_count += count; 3201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds extent->block_count = cpu_to_be32(block_count); 3211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 3221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else if (offset < count) 3231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 3241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds offset -= count; 3251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* panic? */ 3271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EIO; 3281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 3291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int hfsplus_free_extents(struct super_block *sb, 3311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct hfsplus_extent *extent, 3321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u32 offset, u32 block_nr) 3331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 3341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u32 count, start; 3351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int i; 3361b243fd39bd605cdfc482bba4e56b0cb34b28f27Vyacheslav Dubeyko int err = 0; 3371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds hfsplus_dump_extent(extent); 3391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (i = 0; i < 8; extent++, i++) { 3401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds count = be32_to_cpu(extent->block_count); 3411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (offset == count) 3421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto found; 3431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else if (offset < count) 3441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 3451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds offset -= count; 3461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* panic? */ 3481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EIO; 3491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsfound: 3501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (;;) { 3511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds start = be32_to_cpu(extent->start_block); 3521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (count <= block_nr) { 3531b243fd39bd605cdfc482bba4e56b0cb34b28f27Vyacheslav Dubeyko err = hfsplus_block_free(sb, start, count); 3541b243fd39bd605cdfc482bba4e56b0cb34b28f27Vyacheslav Dubeyko if (err) { 355d614267329f2bee7a082ed8781c581c0f3aaa808Joe Perches pr_err("can't free extent\n"); 356c2b3e1f76e5c90215bc7f740b376c0220eb8a8e3Joe Perches hfs_dbg(EXTENT, " start: %u count: %u\n", 3571b243fd39bd605cdfc482bba4e56b0cb34b28f27Vyacheslav Dubeyko start, count); 3581b243fd39bd605cdfc482bba4e56b0cb34b28f27Vyacheslav Dubeyko } 3591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds extent->block_count = 0; 3601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds extent->start_block = 0; 3611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds block_nr -= count; 3621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 3631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds count -= block_nr; 3641b243fd39bd605cdfc482bba4e56b0cb34b28f27Vyacheslav Dubeyko err = hfsplus_block_free(sb, start + count, block_nr); 3651b243fd39bd605cdfc482bba4e56b0cb34b28f27Vyacheslav Dubeyko if (err) { 366d614267329f2bee7a082ed8781c581c0f3aaa808Joe Perches pr_err("can't free extent\n"); 367c2b3e1f76e5c90215bc7f740b376c0220eb8a8e3Joe Perches hfs_dbg(EXTENT, " start: %u count: %u\n", 3681b243fd39bd605cdfc482bba4e56b0cb34b28f27Vyacheslav Dubeyko start, count); 3691b243fd39bd605cdfc482bba4e56b0cb34b28f27Vyacheslav Dubeyko } 3701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds extent->block_count = cpu_to_be32(count); 3711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds block_nr = 0; 3721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3731b243fd39bd605cdfc482bba4e56b0cb34b28f27Vyacheslav Dubeyko if (!block_nr || !i) { 3741b243fd39bd605cdfc482bba4e56b0cb34b28f27Vyacheslav Dubeyko /* 3751b243fd39bd605cdfc482bba4e56b0cb34b28f27Vyacheslav Dubeyko * Try to free all extents and 3761b243fd39bd605cdfc482bba4e56b0cb34b28f27Vyacheslav Dubeyko * return only last error 3771b243fd39bd605cdfc482bba4e56b0cb34b28f27Vyacheslav Dubeyko */ 3781b243fd39bd605cdfc482bba4e56b0cb34b28f27Vyacheslav Dubeyko return err; 3791b243fd39bd605cdfc482bba4e56b0cb34b28f27Vyacheslav Dubeyko } 3801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds i--; 3811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds extent--; 3821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds count = be32_to_cpu(extent->block_count); 3831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 3851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3862753cc281c9a0e8a0a45ee2b8110866a9fe63bddAnton Salikhmetovint hfsplus_free_fork(struct super_block *sb, u32 cnid, 3872753cc281c9a0e8a0a45ee2b8110866a9fe63bddAnton Salikhmetov struct hfsplus_fork_raw *fork, int type) 3881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 3891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct hfs_find_data fd; 3901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds hfsplus_extent_rec ext_entry; 3911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u32 total_blocks, blocks, start; 3921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int res, i; 3931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds total_blocks = be32_to_cpu(fork->total_blocks); 3951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!total_blocks) 3961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 3971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds blocks = 0; 3991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (i = 0; i < 8; i++) 4001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds blocks += be32_to_cpu(fork->extents[i].block_count); 4011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds res = hfsplus_free_extents(sb, fork->extents, blocks, blocks); 4031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (res) 4041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return res; 4051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (total_blocks == blocks) 4061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 4071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4085bd9d99d107c56ff7b35a29e930d85f91a07b2fdAlexey Khoroshilov res = hfs_find_init(HFSPLUS_SB(sb)->ext_tree, &fd); 4095bd9d99d107c56ff7b35a29e930d85f91a07b2fdAlexey Khoroshilov if (res) 4105bd9d99d107c56ff7b35a29e930d85f91a07b2fdAlexey Khoroshilov return res; 4111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds do { 4121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds res = __hfsplus_ext_read_extent(&fd, ext_entry, cnid, 4131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds total_blocks, type); 4141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (res) 4151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 4161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds start = be32_to_cpu(fd.key->ext.start_block); 4171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds hfsplus_free_extents(sb, ext_entry, 4181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds total_blocks - start, 4191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds total_blocks); 4201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds hfs_brec_remove(&fd); 4211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds total_blocks = start; 4221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } while (total_blocks > blocks); 4231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds hfs_find_exit(&fd); 4241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return res; 4261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 4271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4282cd282a1bc6b9d111b8beee63bea0af735a8a1aaSergei Antonovint hfsplus_file_extend(struct inode *inode, bool zeroout) 4291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 4301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct super_block *sb = inode->i_sb; 431dd73a01a30d729e8fa6f829c4582650e258e36f9Christoph Hellwig struct hfsplus_sb_info *sbi = HFSPLUS_SB(sb); 4326af502de224c3742936d54eee7e3690c09822934Christoph Hellwig struct hfsplus_inode_info *hip = HFSPLUS_I(inode); 4331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u32 start, len, goal; 4341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int res; 4351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4361065348d472f97b4b8eb53b60ec67e99148cbbcaChristoph Hellwig if (sbi->alloc_file->i_size * 8 < 4371065348d472f97b4b8eb53b60ec67e99148cbbcaChristoph Hellwig sbi->total_blocks - sbi->free_blocks + 8) { 43821f2296a598c4089e0a9bdf54634269ac913a693Anton Salikhmetov /* extend alloc file */ 439b73f3d0e70b1ff6081980d3fa64e187d1796852cFabian Frederick pr_err("extend alloc file! (%llu,%u,%u)\n", 440b73f3d0e70b1ff6081980d3fa64e187d1796852cFabian Frederick sbi->alloc_file->i_size * 8, 441b73f3d0e70b1ff6081980d3fa64e187d1796852cFabian Frederick sbi->total_blocks, sbi->free_blocks); 4421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -ENOSPC; 4431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 4441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4456af502de224c3742936d54eee7e3690c09822934Christoph Hellwig mutex_lock(&hip->extents_lock); 4466af502de224c3742936d54eee7e3690c09822934Christoph Hellwig if (hip->alloc_blocks == hip->first_blocks) 4476af502de224c3742936d54eee7e3690c09822934Christoph Hellwig goal = hfsplus_ext_lastblock(hip->first_extents); 4481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else { 4496af502de224c3742936d54eee7e3690c09822934Christoph Hellwig res = hfsplus_ext_read_extent(inode, hip->alloc_blocks); 4501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (res) 4511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto out; 4526af502de224c3742936d54eee7e3690c09822934Christoph Hellwig goal = hfsplus_ext_lastblock(hip->cached_extents); 4531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 4541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4556af502de224c3742936d54eee7e3690c09822934Christoph Hellwig len = hip->clump_blocks; 456dd73a01a30d729e8fa6f829c4582650e258e36f9Christoph Hellwig start = hfsplus_block_allocate(sb, sbi->total_blocks, goal, &len); 457dd73a01a30d729e8fa6f829c4582650e258e36f9Christoph Hellwig if (start >= sbi->total_blocks) { 4581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds start = hfsplus_block_allocate(sb, goal, 0, &len); 4591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (start >= goal) { 4601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds res = -ENOSPC; 4611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto out; 4621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 4631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 4641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4652cd282a1bc6b9d111b8beee63bea0af735a8a1aaSergei Antonov if (zeroout) { 4662cd282a1bc6b9d111b8beee63bea0af735a8a1aaSergei Antonov res = sb_issue_zeroout(sb, start, len, GFP_NOFS); 4672cd282a1bc6b9d111b8beee63bea0af735a8a1aaSergei Antonov if (res) 4682cd282a1bc6b9d111b8beee63bea0af735a8a1aaSergei Antonov goto out; 4692cd282a1bc6b9d111b8beee63bea0af735a8a1aaSergei Antonov } 4702cd282a1bc6b9d111b8beee63bea0af735a8a1aaSergei Antonov 471c2b3e1f76e5c90215bc7f740b376c0220eb8a8e3Joe Perches hfs_dbg(EXTENT, "extend %lu: %u,%u\n", inode->i_ino, start, len); 4726af502de224c3742936d54eee7e3690c09822934Christoph Hellwig 4736af502de224c3742936d54eee7e3690c09822934Christoph Hellwig if (hip->alloc_blocks <= hip->first_blocks) { 4746af502de224c3742936d54eee7e3690c09822934Christoph Hellwig if (!hip->first_blocks) { 475c2b3e1f76e5c90215bc7f740b376c0220eb8a8e3Joe Perches hfs_dbg(EXTENT, "first extents\n"); 4761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* no extents yet */ 4776af502de224c3742936d54eee7e3690c09822934Christoph Hellwig hip->first_extents[0].start_block = cpu_to_be32(start); 4786af502de224c3742936d54eee7e3690c09822934Christoph Hellwig hip->first_extents[0].block_count = cpu_to_be32(len); 4791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds res = 0; 4801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 4811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* try to append to extents in inode */ 4826af502de224c3742936d54eee7e3690c09822934Christoph Hellwig res = hfsplus_add_extent(hip->first_extents, 4836af502de224c3742936d54eee7e3690c09822934Christoph Hellwig hip->alloc_blocks, 4841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds start, len); 4851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (res == -ENOSPC) 4861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto insert_extent; 4871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 4881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!res) { 4896af502de224c3742936d54eee7e3690c09822934Christoph Hellwig hfsplus_dump_extent(hip->first_extents); 4906af502de224c3742936d54eee7e3690c09822934Christoph Hellwig hip->first_blocks += len; 4911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 4921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 4936af502de224c3742936d54eee7e3690c09822934Christoph Hellwig res = hfsplus_add_extent(hip->cached_extents, 4946af502de224c3742936d54eee7e3690c09822934Christoph Hellwig hip->alloc_blocks - hip->cached_start, 4951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds start, len); 4961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!res) { 4976af502de224c3742936d54eee7e3690c09822934Christoph Hellwig hfsplus_dump_extent(hip->cached_extents); 498b33b7921db14abcd10c30d0ccfc68e364f5ef7feChristoph Hellwig hip->extent_state |= HFSPLUS_EXT_DIRTY; 4996af502de224c3742936d54eee7e3690c09822934Christoph Hellwig hip->cached_blocks += len; 5001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else if (res == -ENOSPC) 5011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto insert_extent; 5021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 5031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsout: 5041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!res) { 5056af502de224c3742936d54eee7e3690c09822934Christoph Hellwig hip->alloc_blocks += len; 506d7bdb996aef67ea24c62707ca4e29b07025e9683Sougata Santra mutex_unlock(&hip->extents_lock); 507e34947056076ca5467ee8256d2d9cbc594a79b37Christoph Hellwig hfsplus_mark_inode_dirty(inode, HFSPLUS_I_ALLOC_DIRTY); 508d7bdb996aef67ea24c62707ca4e29b07025e9683Sougata Santra return 0; 5091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 510d7bdb996aef67ea24c62707ca4e29b07025e9683Sougata Santra mutex_unlock(&hip->extents_lock); 5111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return res; 5121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsinsert_extent: 514c2b3e1f76e5c90215bc7f740b376c0220eb8a8e3Joe Perches hfs_dbg(EXTENT, "insert new extent\n"); 515dd7f3d5458e5c0eded620fe8192abe7e418fc94cAlexey Khoroshilov res = hfsplus_ext_write_extent_locked(inode); 516dd7f3d5458e5c0eded620fe8192abe7e418fc94cAlexey Khoroshilov if (res) 517dd7f3d5458e5c0eded620fe8192abe7e418fc94cAlexey Khoroshilov goto out; 5181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5196af502de224c3742936d54eee7e3690c09822934Christoph Hellwig memset(hip->cached_extents, 0, sizeof(hfsplus_extent_rec)); 5206af502de224c3742936d54eee7e3690c09822934Christoph Hellwig hip->cached_extents[0].start_block = cpu_to_be32(start); 5216af502de224c3742936d54eee7e3690c09822934Christoph Hellwig hip->cached_extents[0].block_count = cpu_to_be32(len); 5226af502de224c3742936d54eee7e3690c09822934Christoph Hellwig hfsplus_dump_extent(hip->cached_extents); 523b33b7921db14abcd10c30d0ccfc68e364f5ef7feChristoph Hellwig hip->extent_state |= HFSPLUS_EXT_DIRTY | HFSPLUS_EXT_NEW; 5246af502de224c3742936d54eee7e3690c09822934Christoph Hellwig hip->cached_start = hip->alloc_blocks; 5256af502de224c3742936d54eee7e3690c09822934Christoph Hellwig hip->cached_blocks = len; 5261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds res = 0; 5281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto out; 5291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 5301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid hfsplus_file_truncate(struct inode *inode) 5321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 5331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct super_block *sb = inode->i_sb; 5346af502de224c3742936d54eee7e3690c09822934Christoph Hellwig struct hfsplus_inode_info *hip = HFSPLUS_I(inode); 5351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct hfs_find_data fd; 5361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u32 alloc_cnt, blk_cnt, start; 5371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int res; 5381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 539c2b3e1f76e5c90215bc7f740b376c0220eb8a8e3Joe Perches hfs_dbg(INODE, "truncate: %lu, %llu -> %llu\n", 540c2b3e1f76e5c90215bc7f740b376c0220eb8a8e3Joe Perches inode->i_ino, (long long)hip->phys_size, inode->i_size); 5416af502de224c3742936d54eee7e3690c09822934Christoph Hellwig 5426af502de224c3742936d54eee7e3690c09822934Christoph Hellwig if (inode->i_size > hip->phys_size) { 5431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct address_space *mapping = inode->i_mapping; 5441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct page *page; 5457c0efc627738c840a685ea0f2c23d09aad7d5d3bNick Piggin void *fsdata; 54612f267a20aecf8b84a2a9069b9011f1661c779b4Vyacheslav Dubeyko loff_t size = inode->i_size; 5471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5487c0efc627738c840a685ea0f2c23d09aad7d5d3bNick Piggin res = pagecache_write_begin(NULL, mapping, size, 0, 5497c0efc627738c840a685ea0f2c23d09aad7d5d3bNick Piggin AOP_FLAG_UNINTERRUPTIBLE, 5507c0efc627738c840a685ea0f2c23d09aad7d5d3bNick Piggin &page, &fsdata); 5511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (res) 5527c0efc627738c840a685ea0f2c23d09aad7d5d3bNick Piggin return; 5532753cc281c9a0e8a0a45ee2b8110866a9fe63bddAnton Salikhmetov res = pagecache_write_end(NULL, mapping, size, 5542753cc281c9a0e8a0a45ee2b8110866a9fe63bddAnton Salikhmetov 0, 0, page, fsdata); 5557c0efc627738c840a685ea0f2c23d09aad7d5d3bNick Piggin if (res < 0) 5567c0efc627738c840a685ea0f2c23d09aad7d5d3bNick Piggin return; 5571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mark_inode_dirty(inode); 5581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 5596af502de224c3742936d54eee7e3690c09822934Christoph Hellwig } else if (inode->i_size == hip->phys_size) 560f76d28d235cf777dd2e1c1d48c16ee10c1d1587fRoman Zippel return; 561f76d28d235cf777dd2e1c1d48c16ee10c1d1587fRoman Zippel 562dd73a01a30d729e8fa6f829c4582650e258e36f9Christoph Hellwig blk_cnt = (inode->i_size + HFSPLUS_SB(sb)->alloc_blksz - 1) >> 563dd73a01a30d729e8fa6f829c4582650e258e36f9Christoph Hellwig HFSPLUS_SB(sb)->alloc_blksz_shift; 564d7bdb996aef67ea24c62707ca4e29b07025e9683Sougata Santra 565d7bdb996aef67ea24c62707ca4e29b07025e9683Sougata Santra mutex_lock(&hip->extents_lock); 566d7bdb996aef67ea24c62707ca4e29b07025e9683Sougata Santra 5676af502de224c3742936d54eee7e3690c09822934Christoph Hellwig alloc_cnt = hip->alloc_blocks; 5681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (blk_cnt == alloc_cnt) 569d7bdb996aef67ea24c62707ca4e29b07025e9683Sougata Santra goto out_unlock; 5701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5715bd9d99d107c56ff7b35a29e930d85f91a07b2fdAlexey Khoroshilov res = hfs_find_init(HFSPLUS_SB(sb)->ext_tree, &fd); 5725bd9d99d107c56ff7b35a29e930d85f91a07b2fdAlexey Khoroshilov if (res) { 5735bd9d99d107c56ff7b35a29e930d85f91a07b2fdAlexey Khoroshilov mutex_unlock(&hip->extents_lock); 5745bd9d99d107c56ff7b35a29e930d85f91a07b2fdAlexey Khoroshilov /* XXX: We lack error handling of hfsplus_file_truncate() */ 5755bd9d99d107c56ff7b35a29e930d85f91a07b2fdAlexey Khoroshilov return; 5765bd9d99d107c56ff7b35a29e930d85f91a07b2fdAlexey Khoroshilov } 5771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds while (1) { 5786af502de224c3742936d54eee7e3690c09822934Christoph Hellwig if (alloc_cnt == hip->first_blocks) { 5796af502de224c3742936d54eee7e3690c09822934Christoph Hellwig hfsplus_free_extents(sb, hip->first_extents, 5801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds alloc_cnt, alloc_cnt - blk_cnt); 5816af502de224c3742936d54eee7e3690c09822934Christoph Hellwig hfsplus_dump_extent(hip->first_extents); 5826af502de224c3742936d54eee7e3690c09822934Christoph Hellwig hip->first_blocks = blk_cnt; 5831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 5841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 5851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds res = __hfsplus_ext_cache_extent(&fd, inode, alloc_cnt); 5861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (res) 5871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 5886af502de224c3742936d54eee7e3690c09822934Christoph Hellwig start = hip->cached_start; 5896af502de224c3742936d54eee7e3690c09822934Christoph Hellwig hfsplus_free_extents(sb, hip->cached_extents, 5901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds alloc_cnt - start, alloc_cnt - blk_cnt); 5916af502de224c3742936d54eee7e3690c09822934Christoph Hellwig hfsplus_dump_extent(hip->cached_extents); 5921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (blk_cnt > start) { 593b33b7921db14abcd10c30d0ccfc68e364f5ef7feChristoph Hellwig hip->extent_state |= HFSPLUS_EXT_DIRTY; 5941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 5951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 5961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds alloc_cnt = start; 5976af502de224c3742936d54eee7e3690c09822934Christoph Hellwig hip->cached_start = hip->cached_blocks = 0; 598b33b7921db14abcd10c30d0ccfc68e364f5ef7feChristoph Hellwig hip->extent_state &= ~(HFSPLUS_EXT_DIRTY | HFSPLUS_EXT_NEW); 5991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds hfs_brec_remove(&fd); 6001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 6011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds hfs_find_exit(&fd); 6021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6036af502de224c3742936d54eee7e3690c09822934Christoph Hellwig hip->alloc_blocks = blk_cnt; 604d7bdb996aef67ea24c62707ca4e29b07025e9683Sougata Santraout_unlock: 605d7bdb996aef67ea24c62707ca4e29b07025e9683Sougata Santra mutex_unlock(&hip->extents_lock); 6066af502de224c3742936d54eee7e3690c09822934Christoph Hellwig hip->phys_size = inode->i_size; 6072753cc281c9a0e8a0a45ee2b8110866a9fe63bddAnton Salikhmetov hip->fs_blocks = (inode->i_size + sb->s_blocksize - 1) >> 6082753cc281c9a0e8a0a45ee2b8110866a9fe63bddAnton Salikhmetov sb->s_blocksize_bits; 6096af502de224c3742936d54eee7e3690c09822934Christoph Hellwig inode_set_bytes(inode, hip->fs_blocks << sb->s_blocksize_bits); 610e34947056076ca5467ee8256d2d9cbc594a79b37Christoph Hellwig hfsplus_mark_inode_dirty(inode, HFSPLUS_I_ALLOC_DIRTY); 6111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 612