11da177e4SLinus Torvalds /* 21da177e4SLinus Torvalds * linux/fs/hfsplus/inode.c 31da177e4SLinus Torvalds * 41da177e4SLinus Torvalds * Copyright (C) 2001 51da177e4SLinus Torvalds * Brad Boyer (flar@allandria.com) 61da177e4SLinus Torvalds * (C) 2003 Ardis Technologies <roman@ardistech.com> 71da177e4SLinus Torvalds * 81da177e4SLinus Torvalds * Inode handling routines 91da177e4SLinus Torvalds */ 101da177e4SLinus Torvalds 1134a2d313SChristoph Hellwig #include <linux/blkdev.h> 121da177e4SLinus Torvalds #include <linux/mm.h> 131da177e4SLinus Torvalds #include <linux/fs.h> 141da177e4SLinus Torvalds #include <linux/pagemap.h> 151da177e4SLinus Torvalds #include <linux/mpage.h> 16e8edc6e0SAlexey Dobriyan #include <linux/sched.h> 17a27bb332SKent Overstreet #include <linux/aio.h> 181da177e4SLinus Torvalds 191da177e4SLinus Torvalds #include "hfsplus_fs.h" 201da177e4SLinus Torvalds #include "hfsplus_raw.h" 21324ef39aSVyacheslav Dubeyko #include "xattr.h" 22*b4c1107cSVyacheslav Dubeyko #include "acl.h" 231da177e4SLinus Torvalds 241da177e4SLinus Torvalds static int hfsplus_readpage(struct file *file, struct page *page) 251da177e4SLinus Torvalds { 261da177e4SLinus Torvalds return block_read_full_page(page, hfsplus_get_block); 271da177e4SLinus Torvalds } 281da177e4SLinus Torvalds 291da177e4SLinus Torvalds static int hfsplus_writepage(struct page *page, struct writeback_control *wbc) 301da177e4SLinus Torvalds { 311da177e4SLinus Torvalds return block_write_full_page(page, hfsplus_get_block, wbc); 321da177e4SLinus Torvalds } 331da177e4SLinus Torvalds 34d5068485SMarco Stornelli static void hfsplus_write_failed(struct address_space *mapping, loff_t to) 35d5068485SMarco Stornelli { 36d5068485SMarco Stornelli struct inode *inode = mapping->host; 37d5068485SMarco Stornelli 38d5068485SMarco Stornelli if (to > inode->i_size) { 39d5068485SMarco Stornelli truncate_pagecache(inode, to, inode->i_size); 40d5068485SMarco Stornelli hfsplus_file_truncate(inode); 41d5068485SMarco Stornelli } 42d5068485SMarco Stornelli } 43d5068485SMarco Stornelli 447c0efc62SNick Piggin static int hfsplus_write_begin(struct file *file, struct address_space *mapping, 457c0efc62SNick Piggin loff_t pos, unsigned len, unsigned flags, 467c0efc62SNick Piggin struct page **pagep, void **fsdata) 471da177e4SLinus Torvalds { 48282dc178SChristoph Hellwig int ret; 49282dc178SChristoph Hellwig 507c0efc62SNick Piggin *pagep = NULL; 51282dc178SChristoph Hellwig ret = cont_write_begin(file, mapping, pos, len, flags, pagep, fsdata, 527c0efc62SNick Piggin hfsplus_get_block, 536af502deSChristoph Hellwig &HFSPLUS_I(mapping->host)->phys_size); 54d5068485SMarco Stornelli if (unlikely(ret)) 55d5068485SMarco Stornelli hfsplus_write_failed(mapping, pos + len); 56282dc178SChristoph Hellwig 57282dc178SChristoph Hellwig return ret; 581da177e4SLinus Torvalds } 591da177e4SLinus Torvalds 601da177e4SLinus Torvalds static sector_t hfsplus_bmap(struct address_space *mapping, sector_t block) 611da177e4SLinus Torvalds { 621da177e4SLinus Torvalds return generic_block_bmap(mapping, block, hfsplus_get_block); 631da177e4SLinus Torvalds } 641da177e4SLinus Torvalds 6527496a8cSAl Viro static int hfsplus_releasepage(struct page *page, gfp_t mask) 661da177e4SLinus Torvalds { 671da177e4SLinus Torvalds struct inode *inode = page->mapping->host; 681da177e4SLinus Torvalds struct super_block *sb = inode->i_sb; 691da177e4SLinus Torvalds struct hfs_btree *tree; 701da177e4SLinus Torvalds struct hfs_bnode *node; 711da177e4SLinus Torvalds u32 nidx; 721da177e4SLinus Torvalds int i, res = 1; 731da177e4SLinus Torvalds 741da177e4SLinus Torvalds switch (inode->i_ino) { 751da177e4SLinus Torvalds case HFSPLUS_EXT_CNID: 76dd73a01aSChristoph Hellwig tree = HFSPLUS_SB(sb)->ext_tree; 771da177e4SLinus Torvalds break; 781da177e4SLinus Torvalds case HFSPLUS_CAT_CNID: 79dd73a01aSChristoph Hellwig tree = HFSPLUS_SB(sb)->cat_tree; 801da177e4SLinus Torvalds break; 811da177e4SLinus Torvalds case HFSPLUS_ATTR_CNID: 82dd73a01aSChristoph Hellwig tree = HFSPLUS_SB(sb)->attr_tree; 831da177e4SLinus Torvalds break; 841da177e4SLinus Torvalds default: 851da177e4SLinus Torvalds BUG(); 861da177e4SLinus Torvalds return 0; 871da177e4SLinus Torvalds } 8870632249SEric Sesterhenn if (!tree) 8970632249SEric Sesterhenn return 0; 901da177e4SLinus Torvalds if (tree->node_size >= PAGE_CACHE_SIZE) { 912753cc28SAnton Salikhmetov nidx = page->index >> 922753cc28SAnton Salikhmetov (tree->node_size_shift - PAGE_CACHE_SHIFT); 931da177e4SLinus Torvalds spin_lock(&tree->hash_lock); 941da177e4SLinus Torvalds node = hfs_bnode_findhash(tree, nidx); 951da177e4SLinus Torvalds if (!node) 961da177e4SLinus Torvalds ; 971da177e4SLinus Torvalds else if (atomic_read(&node->refcnt)) 981da177e4SLinus Torvalds res = 0; 991da177e4SLinus Torvalds if (res && node) { 1001da177e4SLinus Torvalds hfs_bnode_unhash(node); 1011da177e4SLinus Torvalds hfs_bnode_free(node); 1021da177e4SLinus Torvalds } 1031da177e4SLinus Torvalds spin_unlock(&tree->hash_lock); 1041da177e4SLinus Torvalds } else { 1052753cc28SAnton Salikhmetov nidx = page->index << 1062753cc28SAnton Salikhmetov (PAGE_CACHE_SHIFT - tree->node_size_shift); 1071da177e4SLinus Torvalds i = 1 << (PAGE_CACHE_SHIFT - tree->node_size_shift); 1081da177e4SLinus Torvalds spin_lock(&tree->hash_lock); 1091da177e4SLinus Torvalds do { 1101da177e4SLinus Torvalds node = hfs_bnode_findhash(tree, nidx++); 1111da177e4SLinus Torvalds if (!node) 1121da177e4SLinus Torvalds continue; 1131da177e4SLinus Torvalds if (atomic_read(&node->refcnt)) { 1141da177e4SLinus Torvalds res = 0; 1151da177e4SLinus Torvalds break; 1161da177e4SLinus Torvalds } 1171da177e4SLinus Torvalds hfs_bnode_unhash(node); 1181da177e4SLinus Torvalds hfs_bnode_free(node); 1191da177e4SLinus Torvalds } while (--i && nidx < tree->node_count); 1201da177e4SLinus Torvalds spin_unlock(&tree->hash_lock); 1211da177e4SLinus Torvalds } 1221da177e4SLinus Torvalds return res ? try_to_free_buffers(page) : 0; 1231da177e4SLinus Torvalds } 1241da177e4SLinus Torvalds 1251da177e4SLinus Torvalds static ssize_t hfsplus_direct_IO(int rw, struct kiocb *iocb, 1261da177e4SLinus Torvalds const struct iovec *iov, loff_t offset, unsigned long nr_segs) 1271da177e4SLinus Torvalds { 1281da177e4SLinus Torvalds struct file *file = iocb->ki_filp; 129d5068485SMarco Stornelli struct address_space *mapping = file->f_mapping; 130496ad9aaSAl Viro struct inode *inode = file_inode(file)->i_mapping->host; 131eafdc7d1SChristoph Hellwig ssize_t ret; 1321da177e4SLinus Torvalds 133aacfc19cSChristoph Hellwig ret = blockdev_direct_IO(rw, iocb, inode, iov, offset, nr_segs, 134aacfc19cSChristoph Hellwig hfsplus_get_block); 135eafdc7d1SChristoph Hellwig 136eafdc7d1SChristoph Hellwig /* 137eafdc7d1SChristoph Hellwig * In case of error extending write may have instantiated a few 138eafdc7d1SChristoph Hellwig * blocks outside i_size. Trim these off again. 139eafdc7d1SChristoph Hellwig */ 140eafdc7d1SChristoph Hellwig if (unlikely((rw & WRITE) && ret < 0)) { 141eafdc7d1SChristoph Hellwig loff_t isize = i_size_read(inode); 142eafdc7d1SChristoph Hellwig loff_t end = offset + iov_length(iov, nr_segs); 143eafdc7d1SChristoph Hellwig 144eafdc7d1SChristoph Hellwig if (end > isize) 145d5068485SMarco Stornelli hfsplus_write_failed(mapping, end); 146eafdc7d1SChristoph Hellwig } 147eafdc7d1SChristoph Hellwig 148eafdc7d1SChristoph Hellwig return ret; 1491da177e4SLinus Torvalds } 1501da177e4SLinus Torvalds 1511da177e4SLinus Torvalds static int hfsplus_writepages(struct address_space *mapping, 1521da177e4SLinus Torvalds struct writeback_control *wbc) 1531da177e4SLinus Torvalds { 1541da177e4SLinus Torvalds return mpage_writepages(mapping, wbc, hfsplus_get_block); 1551da177e4SLinus Torvalds } 1561da177e4SLinus Torvalds 157f5e54d6eSChristoph Hellwig const struct address_space_operations hfsplus_btree_aops = { 1581da177e4SLinus Torvalds .readpage = hfsplus_readpage, 1591da177e4SLinus Torvalds .writepage = hfsplus_writepage, 1607c0efc62SNick Piggin .write_begin = hfsplus_write_begin, 1617c0efc62SNick Piggin .write_end = generic_write_end, 1621da177e4SLinus Torvalds .bmap = hfsplus_bmap, 1631da177e4SLinus Torvalds .releasepage = hfsplus_releasepage, 1641da177e4SLinus Torvalds }; 1651da177e4SLinus Torvalds 166f5e54d6eSChristoph Hellwig const struct address_space_operations hfsplus_aops = { 1671da177e4SLinus Torvalds .readpage = hfsplus_readpage, 1681da177e4SLinus Torvalds .writepage = hfsplus_writepage, 1697c0efc62SNick Piggin .write_begin = hfsplus_write_begin, 1707c0efc62SNick Piggin .write_end = generic_write_end, 1711da177e4SLinus Torvalds .bmap = hfsplus_bmap, 1721da177e4SLinus Torvalds .direct_IO = hfsplus_direct_IO, 1731da177e4SLinus Torvalds .writepages = hfsplus_writepages, 1741da177e4SLinus Torvalds }; 1751da177e4SLinus Torvalds 176e16404edSAl Viro const struct dentry_operations hfsplus_dentry_operations = { 177d45bce8fSDuane Griffin .d_hash = hfsplus_hash_dentry, 178d45bce8fSDuane Griffin .d_compare = hfsplus_compare_dentry, 179d45bce8fSDuane Griffin }; 180d45bce8fSDuane Griffin 1812753cc28SAnton Salikhmetov static struct dentry *hfsplus_file_lookup(struct inode *dir, 18200cd8dd3SAl Viro struct dentry *dentry, unsigned int flags) 1831da177e4SLinus Torvalds { 1841da177e4SLinus Torvalds struct hfs_find_data fd; 1851da177e4SLinus Torvalds struct super_block *sb = dir->i_sb; 1861da177e4SLinus Torvalds struct inode *inode = NULL; 1876af502deSChristoph Hellwig struct hfsplus_inode_info *hip; 1881da177e4SLinus Torvalds int err; 1891da177e4SLinus Torvalds 1901da177e4SLinus Torvalds if (HFSPLUS_IS_RSRC(dir) || strcmp(dentry->d_name.name, "rsrc")) 1911da177e4SLinus Torvalds goto out; 1921da177e4SLinus Torvalds 1936af502deSChristoph Hellwig inode = HFSPLUS_I(dir)->rsrc_inode; 1941da177e4SLinus Torvalds if (inode) 1951da177e4SLinus Torvalds goto out; 1961da177e4SLinus Torvalds 1971da177e4SLinus Torvalds inode = new_inode(sb); 1981da177e4SLinus Torvalds if (!inode) 1991da177e4SLinus Torvalds return ERR_PTR(-ENOMEM); 2001da177e4SLinus Torvalds 2016af502deSChristoph Hellwig hip = HFSPLUS_I(inode); 2021da177e4SLinus Torvalds inode->i_ino = dir->i_ino; 2036af502deSChristoph Hellwig INIT_LIST_HEAD(&hip->open_dir_list); 2046af502deSChristoph Hellwig mutex_init(&hip->extents_lock); 205b33b7921SChristoph Hellwig hip->extent_state = 0; 206b33b7921SChristoph Hellwig hip->flags = 0; 207f3922382SMatthew Garrett hip->userflags = 0; 208b33b7921SChristoph Hellwig set_bit(HFSPLUS_I_RSRC, &hip->flags); 2091da177e4SLinus Torvalds 2105bd9d99dSAlexey Khoroshilov err = hfs_find_init(HFSPLUS_SB(sb)->cat_tree, &fd); 2115bd9d99dSAlexey Khoroshilov if (!err) { 2121da177e4SLinus Torvalds err = hfsplus_find_cat(sb, dir->i_ino, &fd); 2131da177e4SLinus Torvalds if (!err) 2141da177e4SLinus Torvalds err = hfsplus_cat_read_inode(inode, &fd); 2151da177e4SLinus Torvalds hfs_find_exit(&fd); 2165bd9d99dSAlexey Khoroshilov } 2171da177e4SLinus Torvalds if (err) { 2181da177e4SLinus Torvalds iput(inode); 2191da177e4SLinus Torvalds return ERR_PTR(err); 2201da177e4SLinus Torvalds } 2216af502deSChristoph Hellwig hip->rsrc_inode = dir; 2226af502deSChristoph Hellwig HFSPLUS_I(dir)->rsrc_inode = inode; 2231da177e4SLinus Torvalds igrab(dir); 22458a818f5SChristoph Hellwig 22558a818f5SChristoph Hellwig /* 22658a818f5SChristoph Hellwig * __mark_inode_dirty expects inodes to be hashed. Since we don't 22758a818f5SChristoph Hellwig * want resource fork inodes in the regular inode space, we make them 22858a818f5SChristoph Hellwig * appear hashed, but do not put on any lists. hlist_del() 22958a818f5SChristoph Hellwig * will work fine and require no locking. 23058a818f5SChristoph Hellwig */ 231756acc2dSAl Viro hlist_add_fake(&inode->i_hash); 23258a818f5SChristoph Hellwig 2331da177e4SLinus Torvalds mark_inode_dirty(inode); 2341da177e4SLinus Torvalds out: 2351da177e4SLinus Torvalds d_add(dentry, inode); 2361da177e4SLinus Torvalds return NULL; 2371da177e4SLinus Torvalds } 2381da177e4SLinus Torvalds 2392753cc28SAnton Salikhmetov static void hfsplus_get_perms(struct inode *inode, 2402753cc28SAnton Salikhmetov struct hfsplus_perm *perms, int dir) 2411da177e4SLinus Torvalds { 242dd73a01aSChristoph Hellwig struct hfsplus_sb_info *sbi = HFSPLUS_SB(inode->i_sb); 2431da177e4SLinus Torvalds u16 mode; 2441da177e4SLinus Torvalds 2451da177e4SLinus Torvalds mode = be16_to_cpu(perms->mode); 2461da177e4SLinus Torvalds 24716525e3fSEric W. Biederman i_uid_write(inode, be32_to_cpu(perms->owner)); 24816525e3fSEric W. Biederman if (!i_uid_read(inode) && !mode) 249dd73a01aSChristoph Hellwig inode->i_uid = sbi->uid; 2501da177e4SLinus Torvalds 25116525e3fSEric W. Biederman i_gid_write(inode, be32_to_cpu(perms->group)); 25216525e3fSEric W. Biederman if (!i_gid_read(inode) && !mode) 253dd73a01aSChristoph Hellwig inode->i_gid = sbi->gid; 2541da177e4SLinus Torvalds 2551da177e4SLinus Torvalds if (dir) { 256dd73a01aSChristoph Hellwig mode = mode ? (mode & S_IALLUGO) : (S_IRWXUGO & ~(sbi->umask)); 2571da177e4SLinus Torvalds mode |= S_IFDIR; 2581da177e4SLinus Torvalds } else if (!mode) 259dd73a01aSChristoph Hellwig mode = S_IFREG | ((S_IRUGO|S_IWUGO) & ~(sbi->umask)); 2601da177e4SLinus Torvalds inode->i_mode = mode; 2611da177e4SLinus Torvalds 2626af502deSChristoph Hellwig HFSPLUS_I(inode)->userflags = perms->userflags; 2631da177e4SLinus Torvalds if (perms->rootflags & HFSPLUS_FLG_IMMUTABLE) 2641da177e4SLinus Torvalds inode->i_flags |= S_IMMUTABLE; 2651da177e4SLinus Torvalds else 2661da177e4SLinus Torvalds inode->i_flags &= ~S_IMMUTABLE; 2671da177e4SLinus Torvalds if (perms->rootflags & HFSPLUS_FLG_APPEND) 2681da177e4SLinus Torvalds inode->i_flags |= S_APPEND; 2691da177e4SLinus Torvalds else 2701da177e4SLinus Torvalds inode->i_flags &= ~S_APPEND; 2711da177e4SLinus Torvalds } 2721da177e4SLinus Torvalds 2731da177e4SLinus Torvalds static int hfsplus_file_open(struct inode *inode, struct file *file) 2741da177e4SLinus Torvalds { 2751da177e4SLinus Torvalds if (HFSPLUS_IS_RSRC(inode)) 2766af502deSChristoph Hellwig inode = HFSPLUS_I(inode)->rsrc_inode; 2776e715294SAlan Cox if (!(file->f_flags & O_LARGEFILE) && i_size_read(inode) > MAX_NON_LFS) 2786e715294SAlan Cox return -EOVERFLOW; 2796af502deSChristoph Hellwig atomic_inc(&HFSPLUS_I(inode)->opencnt); 2801da177e4SLinus Torvalds return 0; 2811da177e4SLinus Torvalds } 2821da177e4SLinus Torvalds 2831da177e4SLinus Torvalds static int hfsplus_file_release(struct inode *inode, struct file *file) 2841da177e4SLinus Torvalds { 2851da177e4SLinus Torvalds struct super_block *sb = inode->i_sb; 2861da177e4SLinus Torvalds 2871da177e4SLinus Torvalds if (HFSPLUS_IS_RSRC(inode)) 2886af502deSChristoph Hellwig inode = HFSPLUS_I(inode)->rsrc_inode; 2896af502deSChristoph Hellwig if (atomic_dec_and_test(&HFSPLUS_I(inode)->opencnt)) { 2901b1dcc1bSJes Sorensen mutex_lock(&inode->i_mutex); 2911da177e4SLinus Torvalds hfsplus_file_truncate(inode); 2921da177e4SLinus Torvalds if (inode->i_flags & S_DEAD) { 293dd73a01aSChristoph Hellwig hfsplus_delete_cat(inode->i_ino, 294dd73a01aSChristoph Hellwig HFSPLUS_SB(sb)->hidden_dir, NULL); 2951da177e4SLinus Torvalds hfsplus_delete_inode(inode); 2961da177e4SLinus Torvalds } 2971b1dcc1bSJes Sorensen mutex_unlock(&inode->i_mutex); 2981da177e4SLinus Torvalds } 2991da177e4SLinus Torvalds return 0; 3001da177e4SLinus Torvalds } 3011da177e4SLinus Torvalds 302d39aae9eSChristoph Hellwig static int hfsplus_setattr(struct dentry *dentry, struct iattr *attr) 303d39aae9eSChristoph Hellwig { 304d39aae9eSChristoph Hellwig struct inode *inode = dentry->d_inode; 305d39aae9eSChristoph Hellwig int error; 306d39aae9eSChristoph Hellwig 307d39aae9eSChristoph Hellwig error = inode_change_ok(inode, attr); 308d39aae9eSChristoph Hellwig if (error) 309d39aae9eSChristoph Hellwig return error; 3101025774cSChristoph Hellwig 3111025774cSChristoph Hellwig if ((attr->ia_valid & ATTR_SIZE) && 3121025774cSChristoph Hellwig attr->ia_size != i_size_read(inode)) { 313562c72aaSChristoph Hellwig inode_dio_wait(inode); 314d5068485SMarco Stornelli truncate_setsize(inode, attr->ia_size); 315d5068485SMarco Stornelli hfsplus_file_truncate(inode); 3161025774cSChristoph Hellwig } 3171025774cSChristoph Hellwig 3181025774cSChristoph Hellwig setattr_copy(inode, attr); 3191025774cSChristoph Hellwig mark_inode_dirty(inode); 320*b4c1107cSVyacheslav Dubeyko 321*b4c1107cSVyacheslav Dubeyko if (attr->ia_valid & ATTR_MODE) { 322*b4c1107cSVyacheslav Dubeyko error = hfsplus_posix_acl_chmod(inode); 323*b4c1107cSVyacheslav Dubeyko if (unlikely(error)) 324*b4c1107cSVyacheslav Dubeyko return error; 325*b4c1107cSVyacheslav Dubeyko } 326*b4c1107cSVyacheslav Dubeyko 3271025774cSChristoph Hellwig return 0; 328d39aae9eSChristoph Hellwig } 329d39aae9eSChristoph Hellwig 33002c24a82SJosef Bacik int hfsplus_file_fsync(struct file *file, loff_t start, loff_t end, 33102c24a82SJosef Bacik int datasync) 332b5fc510cSAl Viro { 33328146976SChristoph Hellwig struct inode *inode = file->f_mapping->host; 334e3494705SChristoph Hellwig struct hfsplus_inode_info *hip = HFSPLUS_I(inode); 33528146976SChristoph Hellwig struct hfsplus_sb_info *sbi = HFSPLUS_SB(inode->i_sb); 336e3494705SChristoph Hellwig int error = 0, error2; 337b5fc510cSAl Viro 33802c24a82SJosef Bacik error = filemap_write_and_wait_range(inode->i_mapping, start, end); 33902c24a82SJosef Bacik if (error) 34002c24a82SJosef Bacik return error; 34102c24a82SJosef Bacik mutex_lock(&inode->i_mutex); 34202c24a82SJosef Bacik 34328146976SChristoph Hellwig /* 34428146976SChristoph Hellwig * Sync inode metadata into the catalog and extent trees. 34528146976SChristoph Hellwig */ 34628146976SChristoph Hellwig sync_inode_metadata(inode, 1); 347b5fc510cSAl Viro 34828146976SChristoph Hellwig /* 34928146976SChristoph Hellwig * And explicitly write out the btrees. 35028146976SChristoph Hellwig */ 351e3494705SChristoph Hellwig if (test_and_clear_bit(HFSPLUS_I_CAT_DIRTY, &hip->flags)) 35228146976SChristoph Hellwig error = filemap_write_and_wait(sbi->cat_tree->inode->i_mapping); 353e3494705SChristoph Hellwig 354e3494705SChristoph Hellwig if (test_and_clear_bit(HFSPLUS_I_EXT_DIRTY, &hip->flags)) { 3552753cc28SAnton Salikhmetov error2 = 3562753cc28SAnton Salikhmetov filemap_write_and_wait(sbi->ext_tree->inode->i_mapping); 35728146976SChristoph Hellwig if (!error) 35828146976SChristoph Hellwig error = error2; 359e3494705SChristoph Hellwig } 360e3494705SChristoph Hellwig 361324ef39aSVyacheslav Dubeyko if (test_and_clear_bit(HFSPLUS_I_ATTR_DIRTY, &hip->flags)) { 362324ef39aSVyacheslav Dubeyko if (sbi->attr_tree) { 363324ef39aSVyacheslav Dubeyko error2 = 364324ef39aSVyacheslav Dubeyko filemap_write_and_wait( 365324ef39aSVyacheslav Dubeyko sbi->attr_tree->inode->i_mapping); 366324ef39aSVyacheslav Dubeyko if (!error) 367324ef39aSVyacheslav Dubeyko error = error2; 368324ef39aSVyacheslav Dubeyko } else { 369d6142673SJoe Perches pr_err("sync non-existent attributes tree\n"); 370324ef39aSVyacheslav Dubeyko } 371324ef39aSVyacheslav Dubeyko } 372324ef39aSVyacheslav Dubeyko 373e3494705SChristoph Hellwig if (test_and_clear_bit(HFSPLUS_I_ALLOC_DIRTY, &hip->flags)) { 37428146976SChristoph Hellwig error2 = filemap_write_and_wait(sbi->alloc_file->i_mapping); 37528146976SChristoph Hellwig if (!error) 37628146976SChristoph Hellwig error = error2; 377e3494705SChristoph Hellwig } 378e3494705SChristoph Hellwig 37934a2d313SChristoph Hellwig if (!test_bit(HFSPLUS_SB_NOBARRIER, &sbi->flags)) 38034a2d313SChristoph Hellwig blkdev_issue_flush(inode->i_sb->s_bdev, GFP_KERNEL, NULL); 38134a2d313SChristoph Hellwig 38202c24a82SJosef Bacik mutex_unlock(&inode->i_mutex); 38302c24a82SJosef Bacik 38428146976SChristoph Hellwig return error; 385b5fc510cSAl Viro } 386b5fc510cSAl Viro 38792e1d5beSArjan van de Ven static const struct inode_operations hfsplus_file_inode_operations = { 3881da177e4SLinus Torvalds .lookup = hfsplus_file_lookup, 389d39aae9eSChristoph Hellwig .setattr = hfsplus_setattr, 390324ef39aSVyacheslav Dubeyko .setxattr = generic_setxattr, 391324ef39aSVyacheslav Dubeyko .getxattr = generic_getxattr, 3921da177e4SLinus Torvalds .listxattr = hfsplus_listxattr, 393324ef39aSVyacheslav Dubeyko .removexattr = hfsplus_removexattr, 394*b4c1107cSVyacheslav Dubeyko #ifdef CONFIG_HFSPLUS_FS_POSIX_ACL 395*b4c1107cSVyacheslav Dubeyko .get_acl = hfsplus_get_posix_acl, 396*b4c1107cSVyacheslav Dubeyko #endif 3971da177e4SLinus Torvalds }; 3981da177e4SLinus Torvalds 3994b6f5d20SArjan van de Ven static const struct file_operations hfsplus_file_operations = { 4001da177e4SLinus Torvalds .llseek = generic_file_llseek, 401543ade1fSBadari Pulavarty .read = do_sync_read, 402543ade1fSBadari Pulavarty .aio_read = generic_file_aio_read, 403543ade1fSBadari Pulavarty .write = do_sync_write, 404543ade1fSBadari Pulavarty .aio_write = generic_file_aio_write, 4051da177e4SLinus Torvalds .mmap = generic_file_mmap, 4065ffc4ef4SJens Axboe .splice_read = generic_file_splice_read, 407b5fc510cSAl Viro .fsync = hfsplus_file_fsync, 4081da177e4SLinus Torvalds .open = hfsplus_file_open, 4091da177e4SLinus Torvalds .release = hfsplus_file_release, 4107cc4bcc6SArnd Bergmann .unlocked_ioctl = hfsplus_ioctl, 4111da177e4SLinus Torvalds }; 4121da177e4SLinus Torvalds 413c47da798SAl Viro struct inode *hfsplus_new_inode(struct super_block *sb, umode_t mode) 4141da177e4SLinus Torvalds { 415dd73a01aSChristoph Hellwig struct hfsplus_sb_info *sbi = HFSPLUS_SB(sb); 4161da177e4SLinus Torvalds struct inode *inode = new_inode(sb); 4176af502deSChristoph Hellwig struct hfsplus_inode_info *hip; 418dd73a01aSChristoph Hellwig 4191da177e4SLinus Torvalds if (!inode) 4201da177e4SLinus Torvalds return NULL; 4211da177e4SLinus Torvalds 422dd73a01aSChristoph Hellwig inode->i_ino = sbi->next_cnid++; 4231da177e4SLinus Torvalds inode->i_mode = mode; 4244ac8489aSDavid Howells inode->i_uid = current_fsuid(); 4254ac8489aSDavid Howells inode->i_gid = current_fsgid(); 426bfe86848SMiklos Szeredi set_nlink(inode, 1); 4271da177e4SLinus Torvalds inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME_SEC; 4286af502deSChristoph Hellwig 4296af502deSChristoph Hellwig hip = HFSPLUS_I(inode); 4306af502deSChristoph Hellwig INIT_LIST_HEAD(&hip->open_dir_list); 4316af502deSChristoph Hellwig mutex_init(&hip->extents_lock); 4326af502deSChristoph Hellwig atomic_set(&hip->opencnt, 0); 433b33b7921SChristoph Hellwig hip->extent_state = 0; 4346af502deSChristoph Hellwig hip->flags = 0; 435f3922382SMatthew Garrett hip->userflags = 0; 4366af502deSChristoph Hellwig memset(hip->first_extents, 0, sizeof(hfsplus_extent_rec)); 4376af502deSChristoph Hellwig memset(hip->cached_extents, 0, sizeof(hfsplus_extent_rec)); 4386af502deSChristoph Hellwig hip->alloc_blocks = 0; 4396af502deSChristoph Hellwig hip->first_blocks = 0; 4406af502deSChristoph Hellwig hip->cached_start = 0; 4416af502deSChristoph Hellwig hip->cached_blocks = 0; 4426af502deSChristoph Hellwig hip->phys_size = 0; 4436af502deSChristoph Hellwig hip->fs_blocks = 0; 4446af502deSChristoph Hellwig hip->rsrc_inode = NULL; 4451da177e4SLinus Torvalds if (S_ISDIR(inode->i_mode)) { 4461da177e4SLinus Torvalds inode->i_size = 2; 447dd73a01aSChristoph Hellwig sbi->folder_count++; 4481da177e4SLinus Torvalds inode->i_op = &hfsplus_dir_inode_operations; 4491da177e4SLinus Torvalds inode->i_fop = &hfsplus_dir_operations; 4501da177e4SLinus Torvalds } else if (S_ISREG(inode->i_mode)) { 451dd73a01aSChristoph Hellwig sbi->file_count++; 4521da177e4SLinus Torvalds inode->i_op = &hfsplus_file_inode_operations; 4531da177e4SLinus Torvalds inode->i_fop = &hfsplus_file_operations; 4541da177e4SLinus Torvalds inode->i_mapping->a_ops = &hfsplus_aops; 4556af502deSChristoph Hellwig hip->clump_blocks = sbi->data_clump_blocks; 4561da177e4SLinus Torvalds } else if (S_ISLNK(inode->i_mode)) { 457dd73a01aSChristoph Hellwig sbi->file_count++; 4581da177e4SLinus Torvalds inode->i_op = &page_symlink_inode_operations; 4591da177e4SLinus Torvalds inode->i_mapping->a_ops = &hfsplus_aops; 4606af502deSChristoph Hellwig hip->clump_blocks = 1; 4611da177e4SLinus Torvalds } else 462dd73a01aSChristoph Hellwig sbi->file_count++; 4631da177e4SLinus Torvalds insert_inode_hash(inode); 4641da177e4SLinus Torvalds mark_inode_dirty(inode); 4659e6c5829SArtem Bityutskiy hfsplus_mark_mdb_dirty(sb); 4661da177e4SLinus Torvalds 4671da177e4SLinus Torvalds return inode; 4681da177e4SLinus Torvalds } 4691da177e4SLinus Torvalds 4701da177e4SLinus Torvalds void hfsplus_delete_inode(struct inode *inode) 4711da177e4SLinus Torvalds { 4721da177e4SLinus Torvalds struct super_block *sb = inode->i_sb; 4731da177e4SLinus Torvalds 4741da177e4SLinus Torvalds if (S_ISDIR(inode->i_mode)) { 475dd73a01aSChristoph Hellwig HFSPLUS_SB(sb)->folder_count--; 4769e6c5829SArtem Bityutskiy hfsplus_mark_mdb_dirty(sb); 4771da177e4SLinus Torvalds return; 4781da177e4SLinus Torvalds } 479dd73a01aSChristoph Hellwig HFSPLUS_SB(sb)->file_count--; 4801da177e4SLinus Torvalds if (S_ISREG(inode->i_mode)) { 4811da177e4SLinus Torvalds if (!inode->i_nlink) { 4821da177e4SLinus Torvalds inode->i_size = 0; 4831da177e4SLinus Torvalds hfsplus_file_truncate(inode); 4841da177e4SLinus Torvalds } 4851da177e4SLinus Torvalds } else if (S_ISLNK(inode->i_mode)) { 4861da177e4SLinus Torvalds inode->i_size = 0; 4871da177e4SLinus Torvalds hfsplus_file_truncate(inode); 4881da177e4SLinus Torvalds } 4899e6c5829SArtem Bityutskiy hfsplus_mark_mdb_dirty(sb); 4901da177e4SLinus Torvalds } 4911da177e4SLinus Torvalds 4921da177e4SLinus Torvalds void hfsplus_inode_read_fork(struct inode *inode, struct hfsplus_fork_raw *fork) 4931da177e4SLinus Torvalds { 4941da177e4SLinus Torvalds struct super_block *sb = inode->i_sb; 495dd73a01aSChristoph Hellwig struct hfsplus_sb_info *sbi = HFSPLUS_SB(sb); 4966af502deSChristoph Hellwig struct hfsplus_inode_info *hip = HFSPLUS_I(inode); 4971da177e4SLinus Torvalds u32 count; 4981da177e4SLinus Torvalds int i; 4991da177e4SLinus Torvalds 5006af502deSChristoph Hellwig memcpy(&hip->first_extents, &fork->extents, sizeof(hfsplus_extent_rec)); 5011da177e4SLinus Torvalds for (count = 0, i = 0; i < 8; i++) 5021da177e4SLinus Torvalds count += be32_to_cpu(fork->extents[i].block_count); 5036af502deSChristoph Hellwig hip->first_blocks = count; 5046af502deSChristoph Hellwig memset(hip->cached_extents, 0, sizeof(hfsplus_extent_rec)); 5056af502deSChristoph Hellwig hip->cached_start = 0; 5066af502deSChristoph Hellwig hip->cached_blocks = 0; 5071da177e4SLinus Torvalds 5086af502deSChristoph Hellwig hip->alloc_blocks = be32_to_cpu(fork->total_blocks); 5096af502deSChristoph Hellwig hip->phys_size = inode->i_size = be64_to_cpu(fork->total_size); 5106af502deSChristoph Hellwig hip->fs_blocks = 5116af502deSChristoph Hellwig (inode->i_size + sb->s_blocksize - 1) >> sb->s_blocksize_bits; 5126af502deSChristoph Hellwig inode_set_bytes(inode, hip->fs_blocks << sb->s_blocksize_bits); 5136af502deSChristoph Hellwig hip->clump_blocks = 514dd73a01aSChristoph Hellwig be32_to_cpu(fork->clump_size) >> sbi->alloc_blksz_shift; 5156af502deSChristoph Hellwig if (!hip->clump_blocks) { 5166af502deSChristoph Hellwig hip->clump_blocks = HFSPLUS_IS_RSRC(inode) ? 517dd73a01aSChristoph Hellwig sbi->rsrc_clump_blocks : 518dd73a01aSChristoph Hellwig sbi->data_clump_blocks; 519dd73a01aSChristoph Hellwig } 5201da177e4SLinus Torvalds } 5211da177e4SLinus Torvalds 5222753cc28SAnton Salikhmetov void hfsplus_inode_write_fork(struct inode *inode, 5232753cc28SAnton Salikhmetov struct hfsplus_fork_raw *fork) 5241da177e4SLinus Torvalds { 5256af502deSChristoph Hellwig memcpy(&fork->extents, &HFSPLUS_I(inode)->first_extents, 5261da177e4SLinus Torvalds sizeof(hfsplus_extent_rec)); 5271da177e4SLinus Torvalds fork->total_size = cpu_to_be64(inode->i_size); 5286af502deSChristoph Hellwig fork->total_blocks = cpu_to_be32(HFSPLUS_I(inode)->alloc_blocks); 5291da177e4SLinus Torvalds } 5301da177e4SLinus Torvalds 5311da177e4SLinus Torvalds int hfsplus_cat_read_inode(struct inode *inode, struct hfs_find_data *fd) 5321da177e4SLinus Torvalds { 5331da177e4SLinus Torvalds hfsplus_cat_entry entry; 5341da177e4SLinus Torvalds int res = 0; 5351da177e4SLinus Torvalds u16 type; 5361da177e4SLinus Torvalds 5371da177e4SLinus Torvalds type = hfs_bnode_read_u16(fd->bnode, fd->entryoffset); 5381da177e4SLinus Torvalds 539f6089ff8SChristoph Hellwig HFSPLUS_I(inode)->linkid = 0; 5401da177e4SLinus Torvalds if (type == HFSPLUS_FOLDER) { 5411da177e4SLinus Torvalds struct hfsplus_cat_folder *folder = &entry.folder; 5421da177e4SLinus Torvalds 5431da177e4SLinus Torvalds if (fd->entrylength < sizeof(struct hfsplus_cat_folder)) 5441da177e4SLinus Torvalds /* panic? */; 5451da177e4SLinus Torvalds hfs_bnode_read(fd->bnode, &entry, fd->entryoffset, 5461da177e4SLinus Torvalds sizeof(struct hfsplus_cat_folder)); 5471da177e4SLinus Torvalds hfsplus_get_perms(inode, &folder->permissions, 1); 548bfe86848SMiklos Szeredi set_nlink(inode, 1); 5491da177e4SLinus Torvalds inode->i_size = 2 + be32_to_cpu(folder->valence); 5501da177e4SLinus Torvalds inode->i_atime = hfsp_mt2ut(folder->access_date); 5511da177e4SLinus Torvalds inode->i_mtime = hfsp_mt2ut(folder->content_mod_date); 5529a4cad95SRoman Zippel inode->i_ctime = hfsp_mt2ut(folder->attribute_mod_date); 5536af502deSChristoph Hellwig HFSPLUS_I(inode)->create_date = folder->create_date; 5546af502deSChristoph Hellwig HFSPLUS_I(inode)->fs_blocks = 0; 5551da177e4SLinus Torvalds inode->i_op = &hfsplus_dir_inode_operations; 5561da177e4SLinus Torvalds inode->i_fop = &hfsplus_dir_operations; 5571da177e4SLinus Torvalds } else if (type == HFSPLUS_FILE) { 5581da177e4SLinus Torvalds struct hfsplus_cat_file *file = &entry.file; 5591da177e4SLinus Torvalds 5601da177e4SLinus Torvalds if (fd->entrylength < sizeof(struct hfsplus_cat_file)) 5611da177e4SLinus Torvalds /* panic? */; 5621da177e4SLinus Torvalds hfs_bnode_read(fd->bnode, &entry, fd->entryoffset, 5631da177e4SLinus Torvalds sizeof(struct hfsplus_cat_file)); 5641da177e4SLinus Torvalds 565b33b7921SChristoph Hellwig hfsplus_inode_read_fork(inode, HFSPLUS_IS_RSRC(inode) ? 566b33b7921SChristoph Hellwig &file->rsrc_fork : &file->data_fork); 5671da177e4SLinus Torvalds hfsplus_get_perms(inode, &file->permissions, 0); 568bfe86848SMiklos Szeredi set_nlink(inode, 1); 5691da177e4SLinus Torvalds if (S_ISREG(inode->i_mode)) { 5701da177e4SLinus Torvalds if (file->permissions.dev) 571bfe86848SMiklos Szeredi set_nlink(inode, 572bfe86848SMiklos Szeredi be32_to_cpu(file->permissions.dev)); 5731da177e4SLinus Torvalds inode->i_op = &hfsplus_file_inode_operations; 5741da177e4SLinus Torvalds inode->i_fop = &hfsplus_file_operations; 5751da177e4SLinus Torvalds inode->i_mapping->a_ops = &hfsplus_aops; 5761da177e4SLinus Torvalds } else if (S_ISLNK(inode->i_mode)) { 5771da177e4SLinus Torvalds inode->i_op = &page_symlink_inode_operations; 5781da177e4SLinus Torvalds inode->i_mapping->a_ops = &hfsplus_aops; 5791da177e4SLinus Torvalds } else { 5801da177e4SLinus Torvalds init_special_inode(inode, inode->i_mode, 5811da177e4SLinus Torvalds be32_to_cpu(file->permissions.dev)); 5821da177e4SLinus Torvalds } 5831da177e4SLinus Torvalds inode->i_atime = hfsp_mt2ut(file->access_date); 5841da177e4SLinus Torvalds inode->i_mtime = hfsp_mt2ut(file->content_mod_date); 5859a4cad95SRoman Zippel inode->i_ctime = hfsp_mt2ut(file->attribute_mod_date); 5866af502deSChristoph Hellwig HFSPLUS_I(inode)->create_date = file->create_date; 5871da177e4SLinus Torvalds } else { 588d6142673SJoe Perches pr_err("bad catalog entry used to create inode\n"); 5891da177e4SLinus Torvalds res = -EIO; 5901da177e4SLinus Torvalds } 5911da177e4SLinus Torvalds return res; 5921da177e4SLinus Torvalds } 5931da177e4SLinus Torvalds 5941da177e4SLinus Torvalds int hfsplus_cat_write_inode(struct inode *inode) 5951da177e4SLinus Torvalds { 5961da177e4SLinus Torvalds struct inode *main_inode = inode; 5971da177e4SLinus Torvalds struct hfs_find_data fd; 5981da177e4SLinus Torvalds hfsplus_cat_entry entry; 5991da177e4SLinus Torvalds 6001da177e4SLinus Torvalds if (HFSPLUS_IS_RSRC(inode)) 6016af502deSChristoph Hellwig main_inode = HFSPLUS_I(inode)->rsrc_inode; 6021da177e4SLinus Torvalds 6031da177e4SLinus Torvalds if (!main_inode->i_nlink) 6041da177e4SLinus Torvalds return 0; 6051da177e4SLinus Torvalds 606dd73a01aSChristoph Hellwig if (hfs_find_init(HFSPLUS_SB(main_inode->i_sb)->cat_tree, &fd)) 6071da177e4SLinus Torvalds /* panic? */ 6081da177e4SLinus Torvalds return -EIO; 6091da177e4SLinus Torvalds 6101da177e4SLinus Torvalds if (hfsplus_find_cat(main_inode->i_sb, main_inode->i_ino, &fd)) 6111da177e4SLinus Torvalds /* panic? */ 6121da177e4SLinus Torvalds goto out; 6131da177e4SLinus Torvalds 6141da177e4SLinus Torvalds if (S_ISDIR(main_inode->i_mode)) { 6151da177e4SLinus Torvalds struct hfsplus_cat_folder *folder = &entry.folder; 6161da177e4SLinus Torvalds 6171da177e4SLinus Torvalds if (fd.entrylength < sizeof(struct hfsplus_cat_folder)) 6181da177e4SLinus Torvalds /* panic? */; 6191da177e4SLinus Torvalds hfs_bnode_read(fd.bnode, &entry, fd.entryoffset, 6201da177e4SLinus Torvalds sizeof(struct hfsplus_cat_folder)); 6211da177e4SLinus Torvalds /* simple node checks? */ 62290e61690SChristoph Hellwig hfsplus_cat_set_perms(inode, &folder->permissions); 6231da177e4SLinus Torvalds folder->access_date = hfsp_ut2mt(inode->i_atime); 6241da177e4SLinus Torvalds folder->content_mod_date = hfsp_ut2mt(inode->i_mtime); 6251da177e4SLinus Torvalds folder->attribute_mod_date = hfsp_ut2mt(inode->i_ctime); 6261da177e4SLinus Torvalds folder->valence = cpu_to_be32(inode->i_size - 2); 6271da177e4SLinus Torvalds hfs_bnode_write(fd.bnode, &entry, fd.entryoffset, 6281da177e4SLinus Torvalds sizeof(struct hfsplus_cat_folder)); 6291da177e4SLinus Torvalds } else if (HFSPLUS_IS_RSRC(inode)) { 6301da177e4SLinus Torvalds struct hfsplus_cat_file *file = &entry.file; 6311da177e4SLinus Torvalds hfs_bnode_read(fd.bnode, &entry, fd.entryoffset, 6321da177e4SLinus Torvalds sizeof(struct hfsplus_cat_file)); 6331da177e4SLinus Torvalds hfsplus_inode_write_fork(inode, &file->rsrc_fork); 6341da177e4SLinus Torvalds hfs_bnode_write(fd.bnode, &entry, fd.entryoffset, 6351da177e4SLinus Torvalds sizeof(struct hfsplus_cat_file)); 6361da177e4SLinus Torvalds } else { 6371da177e4SLinus Torvalds struct hfsplus_cat_file *file = &entry.file; 6381da177e4SLinus Torvalds 6391da177e4SLinus Torvalds if (fd.entrylength < sizeof(struct hfsplus_cat_file)) 6401da177e4SLinus Torvalds /* panic? */; 6411da177e4SLinus Torvalds hfs_bnode_read(fd.bnode, &entry, fd.entryoffset, 6421da177e4SLinus Torvalds sizeof(struct hfsplus_cat_file)); 6431da177e4SLinus Torvalds hfsplus_inode_write_fork(inode, &file->data_fork); 64490e61690SChristoph Hellwig hfsplus_cat_set_perms(inode, &file->permissions); 6452753cc28SAnton Salikhmetov if (HFSPLUS_FLG_IMMUTABLE & 6462753cc28SAnton Salikhmetov (file->permissions.rootflags | 6472753cc28SAnton Salikhmetov file->permissions.userflags)) 6481da177e4SLinus Torvalds file->flags |= cpu_to_be16(HFSPLUS_FILE_LOCKED); 6491da177e4SLinus Torvalds else 6501da177e4SLinus Torvalds file->flags &= cpu_to_be16(~HFSPLUS_FILE_LOCKED); 6511da177e4SLinus Torvalds file->access_date = hfsp_ut2mt(inode->i_atime); 6521da177e4SLinus Torvalds file->content_mod_date = hfsp_ut2mt(inode->i_mtime); 6531da177e4SLinus Torvalds file->attribute_mod_date = hfsp_ut2mt(inode->i_ctime); 6541da177e4SLinus Torvalds hfs_bnode_write(fd.bnode, &entry, fd.entryoffset, 6551da177e4SLinus Torvalds sizeof(struct hfsplus_cat_file)); 6561da177e4SLinus Torvalds } 657e3494705SChristoph Hellwig 658e3494705SChristoph Hellwig set_bit(HFSPLUS_I_CAT_DIRTY, &HFSPLUS_I(inode)->flags); 6591da177e4SLinus Torvalds out: 6601da177e4SLinus Torvalds hfs_find_exit(&fd); 6611da177e4SLinus Torvalds return 0; 6621da177e4SLinus Torvalds } 663