]> git.karo-electronics.de Git - karo-tx-linux.git/commitdiff
Merge branch 'for-next' of git://git.kernel.org/pub/scm/linux/kernel/git/hch/hfsplus
authorLinus Torvalds <torvalds@linux-foundation.org>
Sat, 8 Jan 2011 01:16:27 +0000 (17:16 -0800)
committerLinus Torvalds <torvalds@linux-foundation.org>
Sat, 8 Jan 2011 01:16:27 +0000 (17:16 -0800)
* 'for-next' of git://git.kernel.org/pub/scm/linux/kernel/git/hch/hfsplus:
  hfsplus: %L-to-%ll, macro correction, and remove unneeded braces
  hfsplus: spaces/indentation clean-up
  hfsplus: C99 comments clean-up
  hfsplus: over 80 character lines clean-up
  hfsplus: fix an artifact in ioctl flag checking
  hfsplus: flush disk caches in sync and fsync
  hfsplus: optimize fsync
  hfsplus: split up inode flags
  hfsplus: write up fsync for directories
  hfsplus: simplify fsync
  hfsplus: avoid useless work in hfsplus_sync_fs
  hfsplus: make sure sync writes out all metadata
  hfsplus: use raw bio access for partition tables
  hfsplus: use raw bio access for the volume headers
  hfsplus: always use hfsplus_sync_fs to write the volume header
  hfsplus: silence a few debug printks
  hfsplus: fix option parsing during remount

Fix up conflicts due to VFS changes in fs/hfsplus/{hfsplus_fs.h,unicode.c}

17 files changed:
fs/hfsplus/bfind.c
fs/hfsplus/bitmap.c
fs/hfsplus/bnode.c
fs/hfsplus/brec.c
fs/hfsplus/btree.c
fs/hfsplus/catalog.c
fs/hfsplus/dir.c
fs/hfsplus/extents.c
fs/hfsplus/hfsplus_fs.h
fs/hfsplus/hfsplus_raw.h
fs/hfsplus/inode.c
fs/hfsplus/ioctl.c
fs/hfsplus/options.c
fs/hfsplus/part_tbl.c
fs/hfsplus/super.c
fs/hfsplus/unicode.c
fs/hfsplus/wrapper.c

index d182438c7ae4bea8b4ae108ad910ee795417410a..5d799c13205f5e46e2ae0acb920b866fc92829bf 100644 (file)
@@ -22,7 +22,8 @@ int hfs_find_init(struct hfs_btree *tree, struct hfs_find_data *fd)
                return -ENOMEM;
        fd->search_key = ptr;
        fd->key = ptr + tree->max_key_len + 2;
-       dprint(DBG_BNODE_REFS, "find_init: %d (%p)\n", tree->cnid, __builtin_return_address(0));
+       dprint(DBG_BNODE_REFS, "find_init: %d (%p)\n",
+               tree->cnid, __builtin_return_address(0));
        mutex_lock(&tree->tree_lock);
        return 0;
 }
@@ -31,7 +32,8 @@ void hfs_find_exit(struct hfs_find_data *fd)
 {
        hfs_bnode_put(fd->bnode);
        kfree(fd->search_key);
-       dprint(DBG_BNODE_REFS, "find_exit: %d (%p)\n", fd->tree->cnid, __builtin_return_address(0));
+       dprint(DBG_BNODE_REFS, "find_exit: %d (%p)\n",
+               fd->tree->cnid, __builtin_return_address(0));
        mutex_unlock(&fd->tree->tree_lock);
        fd->tree = NULL;
 }
index ad57f5991eb1f14e3ac24dafa207e440d6d74be3..1cad80c789cb42e5ebada89cc294c9e07fde0d22 100644 (file)
@@ -15,7 +15,8 @@
 
 #define PAGE_CACHE_BITS        (PAGE_CACHE_SIZE * 8)
 
-int hfsplus_block_allocate(struct super_block *sb, u32 size, u32 offset, u32 *max)
+int hfsplus_block_allocate(struct super_block *sb, u32 size,
+               u32 offset, u32 *max)
 {
        struct hfsplus_sb_info *sbi = HFSPLUS_SB(sb);
        struct page *page;
index 29da6574ba77941b22c15b4e959cd4c84b8bbee1..1c42cc5b899f31de94d2cf9dfd24c5e4d451c895 100644 (file)
@@ -42,7 +42,7 @@ void hfs_bnode_read(struct hfs_bnode *node, void *buf, int off, int len)
 u16 hfs_bnode_read_u16(struct hfs_bnode *node, int off)
 {
        __be16 data;
-       // optimize later...
+       /* TODO: optimize later... */
        hfs_bnode_read(node, &data, off, 2);
        return be16_to_cpu(data);
 }
@@ -50,7 +50,7 @@ u16 hfs_bnode_read_u16(struct hfs_bnode *node, int off)
 u8 hfs_bnode_read_u8(struct hfs_bnode *node, int off)
 {
        u8 data;
-       // optimize later...
+       /* TODO: optimize later... */
        hfs_bnode_read(node, &data, off, 1);
        return data;
 }
@@ -96,7 +96,7 @@ void hfs_bnode_write(struct hfs_bnode *node, void *buf, int off, int len)
 void hfs_bnode_write_u16(struct hfs_bnode *node, int off, u16 data)
 {
        __be16 v = cpu_to_be16(data);
-       // optimize later...
+       /* TODO: optimize later... */
        hfs_bnode_write(node, &v, off, 2);
 }
 
@@ -212,7 +212,8 @@ void hfs_bnode_move(struct hfs_bnode *node, int dst, int src, int len)
                                dst_page--;
                        }
                        src -= len;
-                       memmove(kmap(*dst_page) + src, kmap(*src_page) + src, len);
+                       memmove(kmap(*dst_page) + src,
+                               kmap(*src_page) + src, len);
                        kunmap(*src_page);
                        set_page_dirty(*dst_page);
                        kunmap(*dst_page);
@@ -250,14 +251,16 @@ void hfs_bnode_move(struct hfs_bnode *node, int dst, int src, int len)
 
                if (src == dst) {
                        l = min(len, (int)PAGE_CACHE_SIZE - src);
-                       memmove(kmap(*dst_page) + src, kmap(*src_page) + src, l);
+                       memmove(kmap(*dst_page) + src,
+                               kmap(*src_page) + src, l);
                        kunmap(*src_page);
                        set_page_dirty(*dst_page);
                        kunmap(*dst_page);
 
                        while ((len -= l) != 0) {
                                l = min(len, (int)PAGE_CACHE_SIZE);
-                               memmove(kmap(*++dst_page), kmap(*++src_page), l);
+                               memmove(kmap(*++dst_page),
+                                       kmap(*++src_page), l);
                                kunmap(*src_page);
                                set_page_dirty(*dst_page);
                                kunmap(*dst_page);
@@ -268,7 +271,8 @@ void hfs_bnode_move(struct hfs_bnode *node, int dst, int src, int len)
                        do {
                                src_ptr = kmap(*src_page) + src;
                                dst_ptr = kmap(*dst_page) + dst;
-                               if (PAGE_CACHE_SIZE - src < PAGE_CACHE_SIZE - dst) {
+                               if (PAGE_CACHE_SIZE - src <
+                                               PAGE_CACHE_SIZE - dst) {
                                        l = PAGE_CACHE_SIZE - src;
                                        src = 0;
                                        dst += l;
@@ -340,7 +344,8 @@ void hfs_bnode_unlink(struct hfs_bnode *node)
                        return;
                tmp->next = node->next;
                cnid = cpu_to_be32(tmp->next);
-               hfs_bnode_write(tmp, &cnid, offsetof(struct hfs_bnode_desc, next), 4);
+               hfs_bnode_write(tmp, &cnid,
+                       offsetof(struct hfs_bnode_desc, next), 4);
                hfs_bnode_put(tmp);
        } else if (node->type == HFS_NODE_LEAF)
                tree->leaf_head = node->next;
@@ -351,15 +356,15 @@ void hfs_bnode_unlink(struct hfs_bnode *node)
                        return;
                tmp->prev = node->prev;
                cnid = cpu_to_be32(tmp->prev);
-               hfs_bnode_write(tmp, &cnid, offsetof(struct hfs_bnode_desc, prev), 4);
+               hfs_bnode_write(tmp, &cnid,
+                       offsetof(struct hfs_bnode_desc, prev), 4);
                hfs_bnode_put(tmp);
        } else if (node->type == HFS_NODE_LEAF)
                tree->leaf_tail = node->prev;
 
-       // move down?
-       if (!node->prev && !node->next) {
-               printk(KERN_DEBUG "hfs_btree_del_level\n");
-       }
+       /* move down? */
+       if (!node->prev && !node->next)
+               dprint(DBG_BNODE_MOD, "hfs_btree_del_level\n");
        if (!node->parent) {
                tree->root = 0;
                tree->depth = 0;
@@ -379,16 +384,16 @@ struct hfs_bnode *hfs_bnode_findhash(struct hfs_btree *tree, u32 cnid)
        struct hfs_bnode *node;
 
        if (cnid >= tree->node_count) {
-               printk(KERN_ERR "hfs: request for non-existent node %d in B*Tree\n", cnid);
+               printk(KERN_ERR "hfs: request for non-existent node "
+                               "%d in B*Tree\n",
+                       cnid);
                return NULL;
        }
 
        for (node = tree->node_hash[hfs_bnode_hash(cnid)];
-            node; node = node->next_hash) {
-               if (node->this == cnid) {
+                       node; node = node->next_hash)
+               if (node->this == cnid)
                        return node;
-               }
-       }
        return NULL;
 }
 
@@ -402,7 +407,9 @@ static struct hfs_bnode *__hfs_bnode_create(struct hfs_btree *tree, u32 cnid)
        loff_t off;
 
        if (cnid >= tree->node_count) {
-               printk(KERN_ERR "hfs: request for non-existent node %d in B*Tree\n", cnid);
+               printk(KERN_ERR "hfs: request for non-existent node "
+                               "%d in B*Tree\n",
+                       cnid);
                return NULL;
        }
 
@@ -429,7 +436,8 @@ static struct hfs_bnode *__hfs_bnode_create(struct hfs_btree *tree, u32 cnid)
        } else {
                spin_unlock(&tree->hash_lock);
                kfree(node);
-               wait_event(node2->lock_wq, !test_bit(HFS_BNODE_NEW, &node2->flags));
+               wait_event(node2->lock_wq,
+                       !test_bit(HFS_BNODE_NEW, &node2->flags));
                return node2;
        }
        spin_unlock(&tree->hash_lock);
@@ -483,7 +491,8 @@ struct hfs_bnode *hfs_bnode_find(struct hfs_btree *tree, u32 num)
        if (node) {
                hfs_bnode_get(node);
                spin_unlock(&tree->hash_lock);
-               wait_event(node->lock_wq, !test_bit(HFS_BNODE_NEW, &node->flags));
+               wait_event(node->lock_wq,
+                       !test_bit(HFS_BNODE_NEW, &node->flags));
                if (test_bit(HFS_BNODE_ERROR, &node->flags))
                        goto node_error;
                return node;
@@ -497,7 +506,8 @@ struct hfs_bnode *hfs_bnode_find(struct hfs_btree *tree, u32 num)
        if (!test_bit(HFS_BNODE_NEW, &node->flags))
                return node;
 
-       desc = (struct hfs_bnode_desc *)(kmap(node->page[0]) + node->page_offset);
+       desc = (struct hfs_bnode_desc *)(kmap(node->page[0]) +
+                       node->page_offset);
        node->prev = be32_to_cpu(desc->prev);
        node->next = be32_to_cpu(desc->next);
        node->num_recs = be16_to_cpu(desc->num_recs);
@@ -556,11 +566,13 @@ node_error:
 
 void hfs_bnode_free(struct hfs_bnode *node)
 {
-       //int i;
+#if 0
+       int i;
 
-       //for (i = 0; i < node->tree->pages_per_bnode; i++)
-       //      if (node->page[i])
-       //              page_cache_release(node->page[i]);
+       for (i = 0; i < node->tree->pages_per_bnode; i++)
+               if (node->page[i])
+                       page_cache_release(node->page[i]);
+#endif
        kfree(node);
 }
 
@@ -607,7 +619,8 @@ void hfs_bnode_get(struct hfs_bnode *node)
        if (node) {
                atomic_inc(&node->refcnt);
                dprint(DBG_BNODE_REFS, "get_node(%d:%d): %d\n",
-                      node->tree->cnid, node->this, atomic_read(&node->refcnt));
+                       node->tree->cnid, node->this,
+                       atomic_read(&node->refcnt));
        }
 }
 
@@ -619,7 +632,8 @@ void hfs_bnode_put(struct hfs_bnode *node)
                int i;
 
                dprint(DBG_BNODE_REFS, "put_node(%d:%d): %d\n",
-                      node->tree->cnid, node->this, atomic_read(&node->refcnt));
+                       node->tree->cnid, node->this,
+                       atomic_read(&node->refcnt));
                BUG_ON(!atomic_read(&node->refcnt));
                if (!atomic_dec_and_lock(&node->refcnt, &tree->hash_lock))
                        return;
index 2f39d05443e1a374b197359f70d20337562aa9e8..2312de34bd426e0755516042881d3be31ddc33a0 100644 (file)
@@ -39,7 +39,8 @@ u16 hfs_brec_keylen(struct hfs_bnode *node, u16 rec)
           !(node->tree->attributes & HFS_TREE_VARIDXKEYS)) {
                retval = node->tree->max_key_len + 2;
        } else {
-               recoff = hfs_bnode_read_u16(node, node->tree->node_size - (rec + 1) * 2);
+               recoff = hfs_bnode_read_u16(node,
+                       node->tree->node_size - (rec + 1) * 2);
                if (!recoff)
                        return 0;
 
@@ -84,7 +85,8 @@ again:
        end_rec_off = tree->node_size - (node->num_recs + 1) * 2;
        end_off = hfs_bnode_read_u16(node, end_rec_off);
        end_rec_off -= 2;
-       dprint(DBG_BNODE_MOD, "insert_rec: %d, %d, %d, %d\n", rec, size, end_off, end_rec_off);
+       dprint(DBG_BNODE_MOD, "insert_rec: %d, %d, %d, %d\n",
+               rec, size, end_off, end_rec_off);
        if (size > end_rec_off - end_off) {
                if (new_node)
                        panic("not enough room!\n");
@@ -99,7 +101,9 @@ again:
        }
        node->num_recs++;
        /* write new last offset */
-       hfs_bnode_write_u16(node, offsetof(struct hfs_bnode_desc, num_recs), node->num_recs);
+       hfs_bnode_write_u16(node,
+               offsetof(struct hfs_bnode_desc, num_recs),
+               node->num_recs);
        hfs_bnode_write_u16(node, end_rec_off, end_off + size);
        data_off = end_off;
        data_rec_off = end_rec_off + 2;
@@ -151,7 +155,8 @@ skip:
                if (tree->attributes & HFS_TREE_VARIDXKEYS)
                        key_len = be16_to_cpu(fd->search_key->key_len) + 2;
                else {
-                       fd->search_key->key_len = cpu_to_be16(tree->max_key_len);
+                       fd->search_key->key_len =
+                               cpu_to_be16(tree->max_key_len);
                        key_len = tree->max_key_len + 2;
                }
                goto again;
@@ -180,7 +185,8 @@ again:
                mark_inode_dirty(tree->inode);
        }
        hfs_bnode_dump(node);
-       dprint(DBG_BNODE_MOD, "remove_rec: %d, %d\n", fd->record, fd->keylength + fd->entrylength);
+       dprint(DBG_BNODE_MOD, "remove_rec: %d, %d\n",
+               fd->record, fd->keylength + fd->entrylength);
        if (!--node->num_recs) {
                hfs_bnode_unlink(node);
                if (!node->parent)
@@ -194,7 +200,9 @@ again:
                __hfs_brec_find(node, fd);
                goto again;
        }
-       hfs_bnode_write_u16(node, offsetof(struct hfs_bnode_desc, num_recs), node->num_recs);
+       hfs_bnode_write_u16(node,
+               offsetof(struct hfs_bnode_desc, num_recs),
+               node->num_recs);
 
        if (rec_off == end_off)
                goto skip;
@@ -364,7 +372,8 @@ again:
                newkeylen = hfs_bnode_read_u16(node, 14) + 2;
        else
                fd->keylength = newkeylen = tree->max_key_len + 2;
-       dprint(DBG_BNODE_MOD, "update_rec: %d, %d, %d\n", rec, fd->keylength, newkeylen);
+       dprint(DBG_BNODE_MOD, "update_rec: %d, %d, %d\n",
+               rec, fd->keylength, newkeylen);
 
        rec_off = tree->node_size - (rec + 2) * 2;
        end_rec_off = tree->node_size - (parent->num_recs + 1) * 2;
@@ -375,7 +384,7 @@ again:
                end_off = hfs_bnode_read_u16(parent, end_rec_off);
                if (end_rec_off - end_off < diff) {
 
-                       printk(KERN_DEBUG "hfs: splitting index node...\n");
+                       dprint(DBG_BNODE_MOD, "hfs: splitting index node.\n");
                        fd->bnode = parent;
                        new_node = hfs_bnode_split(fd);
                        if (IS_ERR(new_node))
@@ -383,7 +392,8 @@ again:
                        parent = fd->bnode;
                        rec = fd->record;
                        rec_off = tree->node_size - (rec + 2) * 2;
-                       end_rec_off = tree->node_size - (parent->num_recs + 1) * 2;
+                       end_rec_off = tree->node_size -
+                               (parent->num_recs + 1) * 2;
                }
        }
 
index 22e4d4e329999c3ba9848036a3639bc194598f74..21023d9f8ff3d2a9d87b67c6c69efe5606d182ab 100644 (file)
@@ -51,7 +51,8 @@ struct hfs_btree *hfs_btree_open(struct super_block *sb, u32 id)
                goto free_inode;
 
        /* Load the header */
-       head = (struct hfs_btree_header_rec *)(kmap(page) + sizeof(struct hfs_bnode_desc));
+       head = (struct hfs_btree_header_rec *)(kmap(page) +
+               sizeof(struct hfs_bnode_desc));
        tree->root = be32_to_cpu(head->root);
        tree->leaf_count = be32_to_cpu(head->leaf_count);
        tree->leaf_head = be32_to_cpu(head->leaf_head);
@@ -115,7 +116,9 @@ struct hfs_btree *hfs_btree_open(struct super_block *sb, u32 id)
 
        tree->node_size_shift = ffs(size) - 1;
 
-       tree->pages_per_bnode = (tree->node_size + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT;
+       tree->pages_per_bnode =
+               (tree->node_size + PAGE_CACHE_SIZE - 1) >>
+               PAGE_CACHE_SHIFT;
 
        kunmap(page);
        page_cache_release(page);
@@ -144,8 +147,10 @@ void hfs_btree_close(struct hfs_btree *tree)
                while ((node = tree->node_hash[i])) {
                        tree->node_hash[i] = node->next_hash;
                        if (atomic_read(&node->refcnt))
-                               printk(KERN_CRIT "hfs: node %d:%d still has %d user(s)!\n",
-                                       node->tree->cnid, node->this, atomic_read(&node->refcnt));
+                               printk(KERN_CRIT "hfs: node %d:%d "
+                                               "still has %d user(s)!\n",
+                                       node->tree->cnid, node->this,
+                                       atomic_read(&node->refcnt));
                        hfs_bnode_free(node);
                        tree->node_hash_cnt--;
                }
@@ -166,7 +171,8 @@ void hfs_btree_write(struct hfs_btree *tree)
                return;
        /* Load the header */
        page = node->page[0];
-       head = (struct hfs_btree_header_rec *)(kmap(page) + sizeof(struct hfs_bnode_desc));
+       head = (struct hfs_btree_header_rec *)(kmap(page) +
+               sizeof(struct hfs_bnode_desc));
 
        head->root = cpu_to_be32(tree->root);
        head->leaf_count = cpu_to_be32(tree->leaf_count);
@@ -272,7 +278,8 @@ struct hfs_bnode *hfs_bmap_alloc(struct hfs_btree *tree)
                                                tree->free_nodes--;
                                                mark_inode_dirty(tree->inode);
                                                hfs_bnode_put(node);
-                                               return hfs_bnode_create(tree, idx);
+                                               return hfs_bnode_create(tree,
+                                                       idx);
                                        }
                                }
                        }
@@ -287,7 +294,7 @@ struct hfs_bnode *hfs_bmap_alloc(struct hfs_btree *tree)
                kunmap(*pagep);
                nidx = node->next;
                if (!nidx) {
-                       printk(KERN_DEBUG "hfs: create new bmap node...\n");
+                       dprint(DBG_BNODE_MOD, "hfs: create new bmap node.\n");
                        next_node = hfs_bmap_new_bmap(node, idx);
                } else
                        next_node = hfs_bnode_find(tree, nidx);
@@ -329,7 +336,9 @@ void hfs_bmap_free(struct hfs_bnode *node)
                hfs_bnode_put(node);
                if (!i) {
                        /* panic */;
-                       printk(KERN_CRIT "hfs: unable to free bnode %u. bmap not found!\n", node->this);
+                       printk(KERN_CRIT "hfs: unable to free bnode %u. "
+                                       "bmap not found!\n",
+                               node->this);
                        return;
                }
                node = hfs_bnode_find(tree, i);
@@ -337,7 +346,9 @@ void hfs_bmap_free(struct hfs_bnode *node)
                        return;
                if (node->type != HFS_NODE_MAP) {
                        /* panic */;
-                       printk(KERN_CRIT "hfs: invalid bmap found! (%u,%d)\n", node->this, node->type);
+                       printk(KERN_CRIT "hfs: invalid bmap found! "
+                                       "(%u,%d)\n",
+                               node->this, node->type);
                        hfs_bnode_put(node);
                        return;
                }
@@ -350,7 +361,9 @@ void hfs_bmap_free(struct hfs_bnode *node)
        m = 1 << (~nidx & 7);
        byte = data[off];
        if (!(byte & m)) {
-               printk(KERN_CRIT "hfs: trying to free free bnode %u(%d)\n", node->this, node->type);
+               printk(KERN_CRIT "hfs: trying to free free bnode "
+                               "%u(%d)\n",
+                       node->this, node->type);
                kunmap(page);
                hfs_bnode_put(node);
                return;
index 8af45fc5b051abb3353501441fa9ea9030d9395a..b4ba1b3193336ead42c6ffbfbbd365e058cf8f1e 100644 (file)
@@ -91,7 +91,8 @@ void hfsplus_cat_set_perms(struct inode *inode, struct hfsplus_perm *perms)
                perms->dev = 0;
 }
 
-static int hfsplus_cat_build_record(hfsplus_cat_entry *entry, u32 cnid, struct inode *inode)
+static int hfsplus_cat_build_record(hfsplus_cat_entry *entry,
+               u32 cnid, struct inode *inode)
 {
        struct hfsplus_sb_info *sbi = HFSPLUS_SB(inode->i_sb);
 
@@ -128,20 +129,32 @@ static int hfsplus_cat_build_record(hfsplus_cat_entry *entry, u32 cnid, struct i
                if (cnid == inode->i_ino) {
                        hfsplus_cat_set_perms(inode, &file->permissions);
                        if (S_ISLNK(inode->i_mode)) {
-                               file->user_info.fdType = cpu_to_be32(HFSP_SYMLINK_TYPE);
-                               file->user_info.fdCreator = cpu_to_be32(HFSP_SYMLINK_CREATOR);
+                               file->user_info.fdType =
+                                       cpu_to_be32(HFSP_SYMLINK_TYPE);
+                               file->user_info.fdCreator =
+                                       cpu_to_be32(HFSP_SYMLINK_CREATOR);
                        } else {
-                               file->user_info.fdType = cpu_to_be32(sbi->type);
-                               file->user_info.fdCreator = cpu_to_be32(sbi->creator);
+                               file->user_info.fdType =
+                                       cpu_to_be32(sbi->type);
+                               file->user_info.fdCreator =
+                                       cpu_to_be32(sbi->creator);
                        }
-                       if ((file->permissions.rootflags | file->permissions.userflags) & HFSPLUS_FLG_IMMUTABLE)
-                               file->flags |= cpu_to_be16(HFSPLUS_FILE_LOCKED);
+                       if (HFSPLUS_FLG_IMMUTABLE &
+                                       (file->permissions.rootflags |
+                                       file->permissions.userflags))
+                               file->flags |=
+                                       cpu_to_be16(HFSPLUS_FILE_LOCKED);
                } else {
-                       file->user_info.fdType = cpu_to_be32(HFSP_HARDLINK_TYPE);
-                       file->user_info.fdCreator = cpu_to_be32(HFSP_HFSPLUS_CREATOR);
-                       file->user_info.fdFlags = cpu_to_be16(0x100);
-                       file->create_date = HFSPLUS_I(sbi->hidden_dir)->create_date;
-                       file->permissions.dev = cpu_to_be32(HFSPLUS_I(inode)->linkid);
+                       file->user_info.fdType =
+                               cpu_to_be32(HFSP_HARDLINK_TYPE);
+                       file->user_info.fdCreator =
+                               cpu_to_be32(HFSP_HFSPLUS_CREATOR);
+                       file->user_info.fdFlags =
+                               cpu_to_be16(0x100);
+                       file->create_date =
+                               HFSPLUS_I(sbi->hidden_dir)->create_date;
+                       file->permissions.dev =
+                               cpu_to_be32(HFSPLUS_I(inode)->linkid);
                }
                return sizeof(*file);
        }
@@ -182,12 +195,14 @@ int hfsplus_find_cat(struct super_block *sb, u32 cnid,
                return -EIO;
        }
 
-       hfsplus_cat_build_key_uni(fd->search_key, be32_to_cpu(tmp.thread.parentID),
-                                &tmp.thread.nodeName);
+       hfsplus_cat_build_key_uni(fd->search_key,
+               be32_to_cpu(tmp.thread.parentID),
+               &tmp.thread.nodeName);
        return hfs_brec_find(fd);
 }
 
-int hfsplus_create_cat(u32 cnid, struct inode *dir, struct qstr *str, struct inode *inode)
+int hfsplus_create_cat(u32 cnid, struct inode *dir,
+               struct qstr *str, struct inode *inode)
 {
        struct super_block *sb = dir->i_sb;
        struct hfs_find_data fd;
@@ -195,13 +210,15 @@ int hfsplus_create_cat(u32 cnid, struct inode *dir, struct qstr *str, struct ino
        int entry_size;
        int err;
 
-       dprint(DBG_CAT_MOD, "create_cat: %s,%u(%d)\n", str->name, cnid, inode->i_nlink);
+       dprint(DBG_CAT_MOD, "create_cat: %s,%u(%d)\n",
+               str->name, cnid, inode->i_nlink);
        hfs_find_init(HFSPLUS_SB(sb)->cat_tree, &fd);
 
        hfsplus_cat_build_key(sb, fd.search_key, cnid, NULL);
-       entry_size = hfsplus_fill_cat_thread(sb, &entry, S_ISDIR(inode->i_mode) ?
+       entry_size = hfsplus_fill_cat_thread(sb, &entry,
+               S_ISDIR(inode->i_mode) ?
                        HFSPLUS_FOLDER_THREAD : HFSPLUS_FILE_THREAD,
-                       dir->i_ino, str);
+               dir->i_ino, str);
        err = hfs_brec_find(&fd);
        if (err != -ENOENT) {
                if (!err)
@@ -227,7 +244,8 @@ int hfsplus_create_cat(u32 cnid, struct inode *dir, struct qstr *str, struct ino
 
        dir->i_size++;
        dir->i_mtime = dir->i_ctime = CURRENT_TIME_SEC;
-       mark_inode_dirty(dir);
+       hfsplus_mark_inode_dirty(dir, HFSPLUS_I_CAT_DIRTY);
+
        hfs_find_exit(&fd);
        return 0;
 
@@ -249,7 +267,8 @@ int hfsplus_delete_cat(u32 cnid, struct inode *dir, struct qstr *str)
        int err, off;
        u16 type;
 
-       dprint(DBG_CAT_MOD, "delete_cat: %s,%u\n", str ? str->name : NULL, cnid);
+       dprint(DBG_CAT_MOD, "delete_cat: %s,%u\n",
+               str ? str->name : NULL, cnid);
        hfs_find_init(HFSPLUS_SB(sb)->cat_tree, &fd);
 
        if (!str) {
@@ -260,11 +279,15 @@ int hfsplus_delete_cat(u32 cnid, struct inode *dir, struct qstr *str)
                if (err)
                        goto out;
 
-               off = fd.entryoffset + offsetof(struct hfsplus_cat_thread, nodeName);
+               off = fd.entryoffset +
+                       offsetof(struct hfsplus_cat_thread, nodeName);
                fd.search_key->cat.parent = cpu_to_be32(dir->i_ino);
-               hfs_bnode_read(fd.bnode, &fd.search_key->cat.name.length, off, 2);
+               hfs_bnode_read(fd.bnode,
+                       &fd.search_key->cat.name.length, off, 2);
                len = be16_to_cpu(fd.search_key->cat.name.length) * 2;
-               hfs_bnode_read(fd.bnode, &fd.search_key->cat.name.unicode, off + 2, len);
+               hfs_bnode_read(fd.bnode,
+                       &fd.search_key->cat.name.unicode,
+                       off + 2, len);
                fd.search_key->key_len = cpu_to_be16(6 + len);
        } else
                hfsplus_cat_build_key(sb, fd.search_key, dir->i_ino, str);
@@ -281,7 +304,8 @@ int hfsplus_delete_cat(u32 cnid, struct inode *dir, struct qstr *str)
                hfsplus_free_fork(sb, cnid, &fork, HFSPLUS_TYPE_DATA);
 #endif
 
-               off = fd.entryoffset + offsetof(struct hfsplus_cat_file, rsrc_fork);
+               off = fd.entryoffset +
+                       offsetof(struct hfsplus_cat_file, rsrc_fork);
                hfs_bnode_read(fd.bnode, &fork, off, sizeof(fork));
                hfsplus_free_fork(sb, cnid, &fork, HFSPLUS_TYPE_RSRC);
        }
@@ -308,7 +332,7 @@ int hfsplus_delete_cat(u32 cnid, struct inode *dir, struct qstr *str)
 
        dir->i_size--;
        dir->i_mtime = dir->i_ctime = CURRENT_TIME_SEC;
-       mark_inode_dirty(dir);
+       hfsplus_mark_inode_dirty(dir, HFSPLUS_I_CAT_DIRTY);
 out:
        hfs_find_exit(&fd);
 
@@ -325,7 +349,8 @@ int hfsplus_rename_cat(u32 cnid,
        int entry_size, type;
        int err = 0;
 
-       dprint(DBG_CAT_MOD, "rename_cat: %u - %lu,%s - %lu,%s\n", cnid, src_dir->i_ino, src_name->name,
+       dprint(DBG_CAT_MOD, "rename_cat: %u - %lu,%s - %lu,%s\n",
+               cnid, src_dir->i_ino, src_name->name,
                dst_dir->i_ino, dst_name->name);
        hfs_find_init(HFSPLUS_SB(sb)->cat_tree, &src_fd);
        dst_fd = src_fd;
@@ -353,7 +378,6 @@ int hfsplus_rename_cat(u32 cnid,
                goto out;
        dst_dir->i_size++;
        dst_dir->i_mtime = dst_dir->i_ctime = CURRENT_TIME_SEC;
-       mark_inode_dirty(dst_dir);
 
        /* finally remove the old entry */
        hfsplus_cat_build_key(sb, src_fd.search_key, src_dir->i_ino, src_name);
@@ -365,7 +389,6 @@ int hfsplus_rename_cat(u32 cnid,
                goto out;
        src_dir->i_size--;
        src_dir->i_mtime = src_dir->i_ctime = CURRENT_TIME_SEC;
-       mark_inode_dirty(src_dir);
 
        /* remove old thread entry */
        hfsplus_cat_build_key(sb, src_fd.search_key, cnid, NULL);
@@ -379,7 +402,8 @@ int hfsplus_rename_cat(u32 cnid,
 
        /* create new thread entry */
        hfsplus_cat_build_key(sb, dst_fd.search_key, cnid, NULL);
-       entry_size = hfsplus_fill_cat_thread(sb, &entry, type, dst_dir->i_ino, dst_name);
+       entry_size = hfsplus_fill_cat_thread(sb, &entry, type,
+               dst_dir->i_ino, dst_name);
        err = hfs_brec_find(&dst_fd);
        if (err != -ENOENT) {
                if (!err)
@@ -387,6 +411,9 @@ int hfsplus_rename_cat(u32 cnid,
                goto out;
        }
        err = hfs_brec_insert(&dst_fd, &entry, entry_size);
+
+       hfsplus_mark_inode_dirty(dst_dir, HFSPLUS_I_CAT_DIRTY);
+       hfsplus_mark_inode_dirty(src_dir, HFSPLUS_I_CAT_DIRTY);
 out:
        hfs_bnode_put(dst_fd.bnode);
        hfs_find_exit(&src_fd);
index ccab87145f7aa4f9beeda9008142fcd31496c7ed..f896dc843026a278317116c86bd7fa2c75f6cd25 100644 (file)
@@ -66,11 +66,17 @@ again:
                        goto fail;
                }
                cnid = be32_to_cpu(entry.file.id);
-               if (entry.file.user_info.fdType == cpu_to_be32(HFSP_HARDLINK_TYPE) &&
-                   entry.file.user_info.fdCreator == cpu_to_be32(HFSP_HFSPLUS_CREATOR) &&
-                   (entry.file.create_date == HFSPLUS_I(HFSPLUS_SB(sb)->hidden_dir)->create_date ||
-                    entry.file.create_date == HFSPLUS_I(sb->s_root->d_inode)->create_date) &&
-                   HFSPLUS_SB(sb)->hidden_dir) {
+               if (entry.file.user_info.fdType ==
+                               cpu_to_be32(HFSP_HARDLINK_TYPE) &&
+                               entry.file.user_info.fdCreator ==
+                               cpu_to_be32(HFSP_HFSPLUS_CREATOR) &&
+                               (entry.file.create_date ==
+                                       HFSPLUS_I(HFSPLUS_SB(sb)->hidden_dir)->
+                                               create_date ||
+                               entry.file.create_date ==
+                                       HFSPLUS_I(sb->s_root->d_inode)->
+                                               create_date) &&
+                               HFSPLUS_SB(sb)->hidden_dir) {
                        struct qstr str;
                        char name[32];
 
@@ -83,11 +89,13 @@ again:
                                linkid = 0;
                        } else {
                                dentry->d_fsdata = (void *)(unsigned long)cnid;
-                               linkid = be32_to_cpu(entry.file.permissions.dev);
+                               linkid =
+                                       be32_to_cpu(entry.file.permissions.dev);
                                str.len = sprintf(name, "iNode%d", linkid);
                                str.name = name;
                                hfsplus_cat_build_key(sb, fd.search_key,
-                                       HFSPLUS_SB(sb)->hidden_dir->i_ino, &str);
+                                       HFSPLUS_SB(sb)->hidden_dir->i_ino,
+                                       &str);
                                goto again;
                        }
                } else if (!dentry->d_fsdata)
@@ -139,7 +147,8 @@ static int hfsplus_readdir(struct file *filp, void *dirent, filldir_t filldir)
                filp->f_pos++;
                /* fall through */
        case 1:
-               hfs_bnode_read(fd.bnode, &entry, fd.entryoffset, fd.entrylength);
+               hfs_bnode_read(fd.bnode, &entry, fd.entryoffset,
+                       fd.entrylength);
                if (be16_to_cpu(entry.type) != HFSPLUS_FOLDER_THREAD) {
                        printk(KERN_ERR "hfs: bad catalog folder thread\n");
                        err = -EIO;
@@ -169,14 +178,16 @@ static int hfsplus_readdir(struct file *filp, void *dirent, filldir_t filldir)
                        err = -EIO;
                        goto out;
                }
-               hfs_bnode_read(fd.bnode, &entry, fd.entryoffset, fd.entrylength);
+               hfs_bnode_read(fd.bnode, &entry, fd.entryoffset,
+                       fd.entrylength);
                type = be16_to_cpu(entry.type);
                len = HFSPLUS_MAX_STRLEN;
                err = hfsplus_uni2asc(sb, &fd.key->cat.name, strbuf, &len);
                if (err)
                        goto out;
                if (type == HFSPLUS_FOLDER) {
-                       if (fd.entrylength < sizeof(struct hfsplus_cat_folder)) {
+                       if (fd.entrylength <
+                                       sizeof(struct hfsplus_cat_folder)) {
                                printk(KERN_ERR "hfs: small dir entry\n");
                                err = -EIO;
                                goto out;
@@ -202,7 +213,7 @@ static int hfsplus_readdir(struct file *filp, void *dirent, filldir_t filldir)
                        err = -EIO;
                        goto out;
                }
-       next:
+next:
                filp->f_pos++;
                if (filp->f_pos >= inode->i_size)
                        goto out;
@@ -273,7 +284,8 @@ static int hfsplus_link(struct dentry *src_dentry, struct inode *dst_dir,
                HFSPLUS_I(inode)->linkid = id;
                cnid = sbi->next_cnid++;
                src_dentry->d_fsdata = (void *)(unsigned long)cnid;
-               res = hfsplus_create_cat(cnid, src_dir, &src_dentry->d_name, inode);
+               res = hfsplus_create_cat(cnid, src_dir,
+                       &src_dentry->d_name, inode);
                if (res)
                        /* panic? */
                        goto out;
@@ -485,6 +497,7 @@ const struct inode_operations hfsplus_dir_inode_operations = {
 };
 
 const struct file_operations hfsplus_dir_operations = {
+       .fsync          = hfsplus_file_fsync,
        .read           = generic_read_dir,
        .readdir        = hfsplus_readdir,
        .unlocked_ioctl = hfsplus_ioctl,
index 0c9cb1820a523fae02c6bf2f37e6fbdc5c5dceeb..52a0bcaa7b6d7596302d8e2dcf7fba09229c38fd 100644 (file)
@@ -83,7 +83,8 @@ static u32 hfsplus_ext_lastblock(struct hfsplus_extent *ext)
        return be32_to_cpu(ext->start_block) + be32_to_cpu(ext->block_count);
 }
 
-static void __hfsplus_ext_write_extent(struct inode *inode, struct hfs_find_data *fd)
+static void __hfsplus_ext_write_extent(struct inode *inode,
+               struct hfs_find_data *fd)
 {
        struct hfsplus_inode_info *hip = HFSPLUS_I(inode);
        int res;
@@ -95,24 +96,32 @@ static void __hfsplus_ext_write_extent(struct inode *inode, struct hfs_find_data
                                HFSPLUS_TYPE_RSRC : HFSPLUS_TYPE_DATA);
 
        res = hfs_brec_find(fd);
-       if (hip->flags & HFSPLUS_FLG_EXT_NEW) {
+       if (hip->extent_state & HFSPLUS_EXT_NEW) {
                if (res != -ENOENT)
                        return;
                hfs_brec_insert(fd, hip->cached_extents,
                                sizeof(hfsplus_extent_rec));
-               hip->flags &= ~(HFSPLUS_FLG_EXT_DIRTY | HFSPLUS_FLG_EXT_NEW);
+               hip->extent_state &= ~(HFSPLUS_EXT_DIRTY | HFSPLUS_EXT_NEW);
        } else {
                if (res)
                        return;
                hfs_bnode_write(fd->bnode, hip->cached_extents,
                                fd->entryoffset, fd->entrylength);
-               hip->flags &= ~HFSPLUS_FLG_EXT_DIRTY;
+               hip->extent_state &= ~HFSPLUS_EXT_DIRTY;
        }
+
+       /*
+        * We can't just use hfsplus_mark_inode_dirty here, because we
+        * also get called from hfsplus_write_inode, which should not
+        * redirty the inode.  Instead the callers have to be careful
+        * to explicily mark the inode dirty, too.
+        */
+       set_bit(HFSPLUS_I_EXT_DIRTY, &hip->flags);
 }
 
 static void hfsplus_ext_write_extent_locked(struct inode *inode)
 {
-       if (HFSPLUS_I(inode)->flags & HFSPLUS_FLG_EXT_DIRTY) {
+       if (HFSPLUS_I(inode)->extent_state & HFSPLUS_EXT_DIRTY) {
                struct hfs_find_data fd;
 
                hfs_find_init(HFSPLUS_SB(inode->i_sb)->ext_tree, &fd);
@@ -144,18 +153,20 @@ static inline int __hfsplus_ext_read_extent(struct hfs_find_data *fd,
                return -ENOENT;
        if (fd->entrylength != sizeof(hfsplus_extent_rec))
                return -EIO;
-       hfs_bnode_read(fd->bnode, extent, fd->entryoffset, sizeof(hfsplus_extent_rec));
+       hfs_bnode_read(fd->bnode, extent, fd->entryoffset,
+               sizeof(hfsplus_extent_rec));
        return 0;
 }
 
-static inline int __hfsplus_ext_cache_extent(struct hfs_find_data *fd, struct inode *inode, u32 block)
+static inline int __hfsplus_ext_cache_extent(struct hfs_find_data *fd,
+               struct inode *inode, u32 block)
 {
        struct hfsplus_inode_info *hip = HFSPLUS_I(inode);
        int res;
 
        WARN_ON(!mutex_is_locked(&hip->extents_lock));
 
-       if (hip->flags & HFSPLUS_FLG_EXT_DIRTY)
+       if (hip->extent_state & HFSPLUS_EXT_DIRTY)
                __hfsplus_ext_write_extent(inode, fd);
 
        res = __hfsplus_ext_read_extent(fd, hip->cached_extents, inode->i_ino,
@@ -164,10 +175,11 @@ static inline int __hfsplus_ext_cache_extent(struct hfs_find_data *fd, struct in
                                                HFSPLUS_TYPE_DATA);
        if (!res) {
                hip->cached_start = be32_to_cpu(fd->key->ext.start_block);
-               hip->cached_blocks = hfsplus_ext_block_count(hip->cached_extents);
+               hip->cached_blocks =
+                       hfsplus_ext_block_count(hip->cached_extents);
        } else {
                hip->cached_start = hip->cached_blocks = 0;
-               hip->flags &= ~(HFSPLUS_FLG_EXT_DIRTY | HFSPLUS_FLG_EXT_NEW);
+               hip->extent_state &= ~(HFSPLUS_EXT_DIRTY | HFSPLUS_EXT_NEW);
        }
        return res;
 }
@@ -197,6 +209,7 @@ int hfsplus_get_block(struct inode *inode, sector_t iblock,
        struct hfsplus_inode_info *hip = HFSPLUS_I(inode);
        int res = -EIO;
        u32 ablock, dblock, mask;
+       int was_dirty = 0;
        int shift;
 
        /* Convert inode block to disk allocation block */
@@ -223,27 +236,37 @@ int hfsplus_get_block(struct inode *inode, sector_t iblock,
                return -EIO;
 
        mutex_lock(&hip->extents_lock);
+
+       /*
+        * hfsplus_ext_read_extent will write out a cached extent into
+        * the extents btree.  In that case we may have to mark the inode
+        * dirty even for a pure read of an extent here.
+        */
+       was_dirty = (hip->extent_state & HFSPLUS_EXT_DIRTY);
        res = hfsplus_ext_read_extent(inode, ablock);
-       if (!res) {
-               dblock = hfsplus_ext_find_block(hip->cached_extents,
-                                               ablock - hip->cached_start);
-       } else {
+       if (res) {
                mutex_unlock(&hip->extents_lock);
                return -EIO;
        }
+       dblock = hfsplus_ext_find_block(hip->cached_extents,
+                                       ablock - hip->cached_start);
        mutex_unlock(&hip->extents_lock);
 
 done:
-       dprint(DBG_EXTENT, "get_block(%lu): %llu - %u\n", inode->i_ino, (long long)iblock, dblock);
+       dprint(DBG_EXTENT, "get_block(%lu): %llu - %u\n",
+               inode->i_ino, (long long)iblock, dblock);
        mask = (1 << sbi->fs_shift) - 1;
-       map_bh(bh_result, sb, (dblock << sbi->fs_shift) + sbi->blockoffset + (iblock & mask));
+       map_bh(bh_result, sb,
+               (dblock << sbi->fs_shift) + sbi->blockoffset +
+                       (iblock & mask));
        if (create) {
                set_buffer_new(bh_result);
                hip->phys_size += sb->s_blocksize;
                hip->fs_blocks++;
                inode_add_bytes(inode, sb->s_blocksize);
-               mark_inode_dirty(inode);
        }
+       if (create || was_dirty)
+               mark_inode_dirty(inode);
        return 0;
 }
 
@@ -326,7 +349,8 @@ found:
        }
 }
 
-int hfsplus_free_fork(struct super_block *sb, u32 cnid, struct hfsplus_fork_raw *fork, int type)
+int hfsplus_free_fork(struct super_block *sb, u32 cnid,
+               struct hfsplus_fork_raw *fork, int type)
 {
        struct hfs_find_data fd;
        hfsplus_extent_rec ext_entry;
@@ -373,12 +397,13 @@ int hfsplus_file_extend(struct inode *inode)
        u32 start, len, goal;
        int res;
 
-       if (sbi->alloc_file->i_size * 8 <
-           sbi->total_blocks - sbi->free_blocks + 8) {
-               // extend alloc file
-               printk(KERN_ERR "hfs: extend alloc file! (%Lu,%u,%u)\n",
-                               sbi->alloc_file->i_size * 8,
-                               sbi->total_blocks, sbi->free_blocks);
+       if (sbi->total_blocks - sbi->free_blocks + 8 >
+                       sbi->alloc_file->i_size * 8) {
+               /* extend alloc file */
+               printk(KERN_ERR "hfs: extend alloc file! "
+                               "(%llu,%u,%u)\n",
+                       sbi->alloc_file->i_size * 8,
+                       sbi->total_blocks, sbi->free_blocks);
                return -ENOSPC;
        }
 
@@ -429,7 +454,7 @@ int hfsplus_file_extend(struct inode *inode)
                                         start, len);
                if (!res) {
                        hfsplus_dump_extent(hip->cached_extents);
-                       hip->flags |= HFSPLUS_FLG_EXT_DIRTY;
+                       hip->extent_state |= HFSPLUS_EXT_DIRTY;
                        hip->cached_blocks += len;
                } else if (res == -ENOSPC)
                        goto insert_extent;
@@ -438,7 +463,7 @@ out:
        mutex_unlock(&hip->extents_lock);
        if (!res) {
                hip->alloc_blocks += len;
-               mark_inode_dirty(inode);
+               hfsplus_mark_inode_dirty(inode, HFSPLUS_I_ALLOC_DIRTY);
        }
        return res;
 
@@ -450,7 +475,7 @@ insert_extent:
        hip->cached_extents[0].start_block = cpu_to_be32(start);
        hip->cached_extents[0].block_count = cpu_to_be32(len);
        hfsplus_dump_extent(hip->cached_extents);
-       hip->flags |= HFSPLUS_FLG_EXT_DIRTY | HFSPLUS_FLG_EXT_NEW;
+       hip->extent_state |= HFSPLUS_EXT_DIRTY | HFSPLUS_EXT_NEW;
        hip->cached_start = hip->alloc_blocks;
        hip->cached_blocks = len;
 
@@ -466,8 +491,9 @@ void hfsplus_file_truncate(struct inode *inode)
        u32 alloc_cnt, blk_cnt, start;
        int res;
 
-       dprint(DBG_INODE, "truncate: %lu, %Lu -> %Lu\n",
-               inode->i_ino, (long long)hip->phys_size, inode->i_size);
+       dprint(DBG_INODE, "truncate: %lu, %llu -> %llu\n",
+               inode->i_ino, (long long)hip->phys_size,
+               inode->i_size);
 
        if (inode->i_size > hip->phys_size) {
                struct address_space *mapping = inode->i_mapping;
@@ -481,7 +507,8 @@ void hfsplus_file_truncate(struct inode *inode)
                                                &page, &fsdata);
                if (res)
                        return;
-               res = pagecache_write_end(NULL, mapping, size, 0, 0, page, fsdata);
+               res = pagecache_write_end(NULL, mapping, size,
+                       0, 0, page, fsdata);
                if (res < 0)
                        return;
                mark_inode_dirty(inode);
@@ -513,12 +540,12 @@ void hfsplus_file_truncate(struct inode *inode)
                                     alloc_cnt - start, alloc_cnt - blk_cnt);
                hfsplus_dump_extent(hip->cached_extents);
                if (blk_cnt > start) {
-                       hip->flags |= HFSPLUS_FLG_EXT_DIRTY;
+                       hip->extent_state |= HFSPLUS_EXT_DIRTY;
                        break;
                }
                alloc_cnt = start;
                hip->cached_start = hip->cached_blocks = 0;
-               hip->flags &= ~(HFSPLUS_FLG_EXT_DIRTY | HFSPLUS_FLG_EXT_NEW);
+               hip->extent_state &= ~(HFSPLUS_EXT_DIRTY | HFSPLUS_EXT_NEW);
                hfs_brec_remove(&fd);
        }
        hfs_find_exit(&fd);
@@ -527,7 +554,8 @@ void hfsplus_file_truncate(struct inode *inode)
        hip->alloc_blocks = blk_cnt;
 out:
        hip->phys_size = inode->i_size;
-       hip->fs_blocks = (inode->i_size + sb->s_blocksize - 1) >> sb->s_blocksize_bits;
+       hip->fs_blocks = (inode->i_size + sb->s_blocksize - 1) >>
+               sb->s_blocksize_bits;
        inode_set_bytes(inode, hip->fs_blocks << sb->s_blocksize_bits);
-       mark_inode_dirty(inode);
+       hfsplus_mark_inode_dirty(inode, HFSPLUS_I_ALLOC_DIRTY);
 }
index a5308f491e3ef5c3b65d62bcaaf3b29ce51c42da..d6857523336d21412ec50bb0a8c8039526ab6adb 100644 (file)
 #define DBG_EXTENT     0x00000020
 #define DBG_BITMAP     0x00000040
 
-//#define DBG_MASK     (DBG_EXTENT|DBG_INODE|DBG_BNODE_MOD)
-//#define DBG_MASK     (DBG_BNODE_MOD|DBG_CAT_MOD|DBG_INODE)
-//#define DBG_MASK     (DBG_CAT_MOD|DBG_BNODE_REFS|DBG_INODE|DBG_EXTENT)
+#if 0
+#define DBG_MASK       (DBG_EXTENT|DBG_INODE|DBG_BNODE_MOD)
+#define DBG_MASK       (DBG_BNODE_MOD|DBG_CAT_MOD|DBG_INODE)
+#define DBG_MASK       (DBG_CAT_MOD|DBG_BNODE_REFS|DBG_INODE|DBG_EXTENT)
+#endif
 #define DBG_MASK       (0)
 
 #define dprint(flg, fmt, args...) \
-       if (flg & DBG_MASK) printk(fmt , ## args)
+       if (flg & DBG_MASK) \
+               printk(fmt , ## args)
 
 /* Runtime config options */
 #define HFSPLUS_DEF_CR_TYPE    0x3F3F3F3F  /* '????' */
@@ -37,7 +40,8 @@
 #define HFSPLUS_TYPE_DATA 0x00
 #define HFSPLUS_TYPE_RSRC 0xFF
 
-typedef int (*btree_keycmp)(const hfsplus_btree_key *, const hfsplus_btree_key *);
+typedef int (*btree_keycmp)(const hfsplus_btree_key *,
+               const hfsplus_btree_key *);
 
 #define NODE_HASH_SIZE 256
 
@@ -61,7 +65,6 @@ struct hfs_btree {
        unsigned int max_key_len;
        unsigned int depth;
 
-       //unsigned int map1_size, map_size;
        struct mutex tree_lock;
 
        unsigned int pages_per_bnode;
@@ -107,8 +110,8 @@ struct hfsplus_vh;
 struct hfs_btree;
 
 struct hfsplus_sb_info {
-       struct buffer_head *s_vhbh;
        struct hfsplus_vh *s_vhdr;
+       struct hfsplus_vh *s_backup_vhdr;
        struct hfs_btree *ext_tree;
        struct hfs_btree *cat_tree;
        struct hfs_btree *attr_tree;
@@ -118,7 +121,8 @@ struct hfsplus_sb_info {
 
        /* Runtime variables */
        u32 blockoffset;
-       u32 sect_count;
+       sector_t part_start;
+       sector_t sect_count;
        int fs_shift;
 
        /* immutable data from the volume header */
@@ -155,6 +159,12 @@ struct hfsplus_sb_info {
 #define HFSPLUS_SB_FORCE       2
 #define HFSPLUS_SB_HFSX                3
 #define HFSPLUS_SB_CASEFOLD    4
+#define HFSPLUS_SB_NOBARRIER   5
+
+static inline struct hfsplus_sb_info *HFSPLUS_SB(struct super_block *sb)
+{
+       return sb->s_fs_info;
+}
 
 
 struct hfsplus_inode_info {
@@ -170,7 +180,7 @@ struct hfsplus_inode_info {
        u32 cached_blocks;
        hfsplus_extent_rec first_extents;
        hfsplus_extent_rec cached_extents;
-       unsigned long flags;
+       unsigned int extent_state;
        struct mutex extents_lock;
 
        /*
@@ -184,6 +194,11 @@ struct hfsplus_inode_info {
         */
        u32 linkid;
 
+       /*
+        * Accessed using atomic bitops.
+        */
+       unsigned long flags;
+
        /*
         * Protected by i_mutex.
         */
@@ -195,12 +210,34 @@ struct hfsplus_inode_info {
        struct inode vfs_inode;
 };
 
-#define HFSPLUS_FLG_RSRC       0x0001
-#define HFSPLUS_FLG_EXT_DIRTY  0x0002
-#define HFSPLUS_FLG_EXT_NEW    0x0004
+#define HFSPLUS_EXT_DIRTY      0x0001
+#define HFSPLUS_EXT_NEW                0x0002
+
+#define HFSPLUS_I_RSRC         0       /* represents a resource fork */
+#define HFSPLUS_I_CAT_DIRTY    1       /* has changes in the catalog tree */
+#define HFSPLUS_I_EXT_DIRTY    2       /* has changes in the extent tree */
+#define HFSPLUS_I_ALLOC_DIRTY  3       /* has changes in the allocation file */
+
+#define HFSPLUS_IS_RSRC(inode) \
+       test_bit(HFSPLUS_I_RSRC, &HFSPLUS_I(inode)->flags)
+
+static inline struct hfsplus_inode_info *HFSPLUS_I(struct inode *inode)
+{
+       return list_entry(inode, struct hfsplus_inode_info, vfs_inode);
+}
 
-#define HFSPLUS_IS_DATA(inode)   (!(HFSPLUS_I(inode)->flags & HFSPLUS_FLG_RSRC))
-#define HFSPLUS_IS_RSRC(inode)   (HFSPLUS_I(inode)->flags & HFSPLUS_FLG_RSRC)
+/*
+ * Mark an inode dirty, and also mark the btree in which the
+ * specific type of metadata is stored.
+ * For data or metadata that gets written back by into the catalog btree
+ * by hfsplus_write_inode a plain mark_inode_dirty call is enough.
+ */
+static inline void hfsplus_mark_inode_dirty(struct inode *inode,
+               unsigned int flag)
+{
+       set_bit(flag, &HFSPLUS_I(inode)->flags);
+       mark_inode_dirty(inode);
+}
 
 struct hfs_find_data {
        /* filled by caller */
@@ -318,9 +355,12 @@ int hfs_brec_read(struct hfs_find_data *, void *, int);
 int hfs_brec_goto(struct hfs_find_data *, int);
 
 /* catalog.c */
-int hfsplus_cat_case_cmp_key(const hfsplus_btree_key *, const hfsplus_btree_key *);
-int hfsplus_cat_bin_cmp_key(const hfsplus_btree_key *, const hfsplus_btree_key *);
-void hfsplus_cat_build_key(struct super_block *sb, hfsplus_btree_key *, u32, struct qstr *);
+int hfsplus_cat_case_cmp_key(const hfsplus_btree_key *,
+               const hfsplus_btree_key *);
+int hfsplus_cat_bin_cmp_key(const hfsplus_btree_key *,
+               const hfsplus_btree_key *);
+void hfsplus_cat_build_key(struct super_block *sb,
+               hfsplus_btree_key *, u32, struct qstr *);
 int hfsplus_find_cat(struct super_block *, u32, struct hfs_find_data *);
 int hfsplus_create_cat(u32, struct inode *, struct qstr *, struct inode *);
 int hfsplus_delete_cat(u32, struct inode *, struct qstr *);
@@ -336,7 +376,8 @@ extern const struct file_operations hfsplus_dir_operations;
 int hfsplus_ext_cmp_key(const hfsplus_btree_key *, const hfsplus_btree_key *);
 void hfsplus_ext_write_extent(struct inode *);
 int hfsplus_get_block(struct inode *, sector_t, struct buffer_head *, int);
-int hfsplus_free_fork(struct super_block *, u32, struct hfsplus_fork_raw *, int);
+int hfsplus_free_fork(struct super_block *, u32,
+               struct hfsplus_fork_raw *, int);
 int hfsplus_file_extend(struct inode *);
 void hfsplus_file_truncate(struct inode *);
 
@@ -351,6 +392,7 @@ int hfsplus_cat_read_inode(struct inode *, struct hfs_find_data *);
 int hfsplus_cat_write_inode(struct inode *);
 struct inode *hfsplus_new_inode(struct super_block *, int);
 void hfsplus_delete_inode(struct inode *);
+int hfsplus_file_fsync(struct file *file, int datasync);
 
 /* ioctl.c */
 long hfsplus_ioctl(struct file *filp, unsigned int cmd, unsigned long arg);
@@ -362,6 +404,7 @@ ssize_t hfsplus_listxattr(struct dentry *dentry, char *buffer, size_t size);
 
 /* options.c */
 int hfsplus_parse_options(char *, struct hfsplus_sb_info *);
+int hfsplus_parse_options_remount(char *input, int *force);
 void hfsplus_fill_defaults(struct hfsplus_sb_info *);
 int hfsplus_show_options(struct seq_file *, struct vfsmount *);
 
@@ -375,12 +418,16 @@ extern u16 hfsplus_decompose_table[];
 extern u16 hfsplus_compose_table[];
 
 /* unicode.c */
-int hfsplus_strcasecmp(const struct hfsplus_unistr *, const struct hfsplus_unistr *);
-int hfsplus_strcmp(const struct hfsplus_unistr *, const struct hfsplus_unistr *);
-int hfsplus_uni2asc(struct super_block *, const struct hfsplus_unistr *, char *, int *);
-int hfsplus_asc2uni(struct super_block *, struct hfsplus_unistr *, const char *, int);
-int hfsplus_hash_dentry(const struct dentry *dentry, const struct inode *inode,
-               struct qstr *str);
+int hfsplus_strcasecmp(const struct hfsplus_unistr *,
+               const struct hfsplus_unistr *);
+int hfsplus_strcmp(const struct hfsplus_unistr *,
+               const struct hfsplus_unistr *);
+int hfsplus_uni2asc(struct super_block *,
+               const struct hfsplus_unistr *, char *, int *);
+int hfsplus_asc2uni(struct super_block *,
+               struct hfsplus_unistr *, const char *, int);
+int hfsplus_hash_dentry(const struct dentry *dentry,
+               const struct inode *inode, struct qstr *str);
 int hfsplus_compare_dentry(const struct dentry *parent,
                const struct inode *pinode,
                const struct dentry *dentry, const struct inode *inode,
@@ -388,36 +435,9 @@ int hfsplus_compare_dentry(const struct dentry *parent,
 
 /* wrapper.c */
 int hfsplus_read_wrapper(struct super_block *);
-
 int hfs_part_find(struct super_block *, sector_t *, sector_t *);
-
-/* access macros */
-static inline struct hfsplus_sb_info *HFSPLUS_SB(struct super_block *sb)
-{
-       return sb->s_fs_info;
-}
-
-static inline struct hfsplus_inode_info *HFSPLUS_I(struct inode *inode)
-{
-       return list_entry(inode, struct hfsplus_inode_info, vfs_inode);
-}
-
-#define sb_bread512(sb, sec, data) ({                  \
-       struct buffer_head *__bh;                       \
-       sector_t __block;                               \
-       loff_t __start;                                 \
-       int __offset;                                   \
-                                                       \
-       __start = (loff_t)(sec) << HFSPLUS_SECTOR_SHIFT;\
-       __block = __start >> (sb)->s_blocksize_bits;    \
-       __offset = __start & ((sb)->s_blocksize - 1);   \
-       __bh = sb_bread((sb), __block);                 \
-       if (likely(__bh != NULL))                       \
-               data = (void *)(__bh->b_data + __offset);\
-       else                                            \
-               data = NULL;                            \
-       __bh;                                           \
-})
+int hfsplus_submit_bio(struct block_device *bdev, sector_t sector,
+               void *data, int rw);
 
 /* time macros */
 #define __hfsp_mt2ut(t)                (be32_to_cpu(t) - 2082844800U)
index 6892899fd6fbbabce55d3fe1f2c8915fe3f33d89..927cdd6d5bf59b667f6b43ca00c0c0e5034e55b7 100644 (file)
@@ -36,7 +36,8 @@
 #define HFSP_WRAPOFF_EMBEDSIG     0x7C
 #define HFSP_WRAPOFF_EMBEDEXT     0x7E
 
-#define HFSP_HIDDENDIR_NAME    "\xe2\x90\x80\xe2\x90\x80\xe2\x90\x80\xe2\x90\x80HFS+ Private Data"
+#define HFSP_HIDDENDIR_NAME \
+       "\xe2\x90\x80\xe2\x90\x80\xe2\x90\x80\xe2\x90\x80HFS+ Private Data"
 
 #define HFSP_HARDLINK_TYPE     0x686c6e6b      /* 'hlnk' */
 #define HFSP_HFSPLUS_CREATOR   0x6866732b      /* 'hfs+' */
index 8afd7e84f98d5d0417b8c256d60f0ff0329521db..a8df651747f0eadaa8af44dffda657f2d64aea3d 100644 (file)
@@ -8,6 +8,7 @@
  * Inode handling routines
  */
 
+#include <linux/blkdev.h>
 #include <linux/mm.h>
 #include <linux/fs.h>
 #include <linux/pagemap.h>
@@ -77,7 +78,8 @@ static int hfsplus_releasepage(struct page *page, gfp_t mask)
        if (!tree)
                return 0;
        if (tree->node_size >= PAGE_CACHE_SIZE) {
-               nidx = page->index >> (tree->node_size_shift - PAGE_CACHE_SHIFT);
+               nidx = page->index >>
+                       (tree->node_size_shift - PAGE_CACHE_SHIFT);
                spin_lock(&tree->hash_lock);
                node = hfs_bnode_findhash(tree, nidx);
                if (!node)
@@ -90,7 +92,8 @@ static int hfsplus_releasepage(struct page *page, gfp_t mask)
                }
                spin_unlock(&tree->hash_lock);
        } else {
-               nidx = page->index << (PAGE_CACHE_SHIFT - tree->node_size_shift);
+               nidx = page->index <<
+                       (PAGE_CACHE_SHIFT - tree->node_size_shift);
                i = 1 << (PAGE_CACHE_SHIFT - tree->node_size_shift);
                spin_lock(&tree->hash_lock);
                do {
@@ -166,8 +169,8 @@ const struct dentry_operations hfsplus_dentry_operations = {
        .d_compare    = hfsplus_compare_dentry,
 };
 
-static struct dentry *hfsplus_file_lookup(struct inode *dir, struct dentry *dentry,
-                                         struct nameidata *nd)
+static struct dentry *hfsplus_file_lookup(struct inode *dir,
+               struct dentry *dentry, struct nameidata *nd)
 {
        struct hfs_find_data fd;
        struct super_block *sb = dir->i_sb;
@@ -190,7 +193,9 @@ static struct dentry *hfsplus_file_lookup(struct inode *dir, struct dentry *dent
        inode->i_ino = dir->i_ino;
        INIT_LIST_HEAD(&hip->open_dir_list);
        mutex_init(&hip->extents_lock);
-       hip->flags = HFSPLUS_FLG_RSRC;
+       hip->extent_state = 0;
+       hip->flags = 0;
+       set_bit(HFSPLUS_I_RSRC, &hip->flags);
 
        hfs_find_init(HFSPLUS_SB(sb)->cat_tree, &fd);
        err = hfsplus_find_cat(sb, dir->i_ino, &fd);
@@ -219,7 +224,8 @@ out:
        return NULL;
 }
 
-static void hfsplus_get_perms(struct inode *inode, struct hfsplus_perm *perms, int dir)
+static void hfsplus_get_perms(struct inode *inode,
+               struct hfsplus_perm *perms, int dir)
 {
        struct hfsplus_sb_info *sbi = HFSPLUS_SB(inode->i_sb);
        u16 mode;
@@ -302,29 +308,41 @@ static int hfsplus_setattr(struct dentry *dentry, struct iattr *attr)
        return 0;
 }
 
-static int hfsplus_file_fsync(struct file *filp, int datasync)
+int hfsplus_file_fsync(struct file *file, int datasync)
 {
-       struct inode *inode = filp->f_mapping->host;
-       struct super_block * sb;
-       int ret, err;
-
-       /* sync the inode to buffers */
-       ret = write_inode_now(inode, 0);
-
-       /* sync the superblock to buffers */
-       sb = inode->i_sb;
-       if (sb->s_dirt) {
-               if (!(sb->s_flags & MS_RDONLY))
-                       hfsplus_sync_fs(sb, 1);
-               else
-                       sb->s_dirt = 0;
+       struct inode *inode = file->f_mapping->host;
+       struct hfsplus_inode_info *hip = HFSPLUS_I(inode);
+       struct hfsplus_sb_info *sbi = HFSPLUS_SB(inode->i_sb);
+       int error = 0, error2;
+
+       /*
+        * Sync inode metadata into the catalog and extent trees.
+        */
+       sync_inode_metadata(inode, 1);
+
+       /*
+        * And explicitly write out the btrees.
+        */
+       if (test_and_clear_bit(HFSPLUS_I_CAT_DIRTY, &hip->flags))
+               error = filemap_write_and_wait(sbi->cat_tree->inode->i_mapping);
+
+       if (test_and_clear_bit(HFSPLUS_I_EXT_DIRTY, &hip->flags)) {
+               error2 =
+                       filemap_write_and_wait(sbi->ext_tree->inode->i_mapping);
+               if (!error)
+                       error = error2;
        }
 
-       /* .. finally sync the buffers to disk */
-       err = sync_blockdev(sb->s_bdev);
-       if (!ret)
-               ret = err;
-       return ret;
+       if (test_and_clear_bit(HFSPLUS_I_ALLOC_DIRTY, &hip->flags)) {
+               error2 = filemap_write_and_wait(sbi->alloc_file->i_mapping);
+               if (!error)
+                       error = error2;
+       }
+
+       if (!test_bit(HFSPLUS_SB_NOBARRIER, &sbi->flags))
+               blkdev_issue_flush(inode->i_sb->s_bdev, GFP_KERNEL, NULL);
+
+       return error;
 }
 
 static const struct inode_operations hfsplus_file_inode_operations = {
@@ -337,7 +355,7 @@ static const struct inode_operations hfsplus_file_inode_operations = {
 };
 
 static const struct file_operations hfsplus_file_operations = {
-       .llseek         = generic_file_llseek,
+       .llseek         = generic_file_llseek,
        .read           = do_sync_read,
        .aio_read       = generic_file_aio_read,
        .write          = do_sync_write,
@@ -370,6 +388,7 @@ struct inode *hfsplus_new_inode(struct super_block *sb, int mode)
        INIT_LIST_HEAD(&hip->open_dir_list);
        mutex_init(&hip->extents_lock);
        atomic_set(&hip->opencnt, 0);
+       hip->extent_state = 0;
        hip->flags = 0;
        memset(hip->first_extents, 0, sizeof(hfsplus_extent_rec));
        memset(hip->cached_extents, 0, sizeof(hfsplus_extent_rec));
@@ -457,7 +476,8 @@ void hfsplus_inode_read_fork(struct inode *inode, struct hfsplus_fork_raw *fork)
        }
 }
 
-void hfsplus_inode_write_fork(struct inode *inode, struct hfsplus_fork_raw *fork)
+void hfsplus_inode_write_fork(struct inode *inode,
+               struct hfsplus_fork_raw *fork)
 {
        memcpy(&fork->extents, &HFSPLUS_I(inode)->first_extents,
               sizeof(hfsplus_extent_rec));
@@ -499,13 +519,14 @@ int hfsplus_cat_read_inode(struct inode *inode, struct hfs_find_data *fd)
                hfs_bnode_read(fd->bnode, &entry, fd->entryoffset,
                                        sizeof(struct hfsplus_cat_file));
 
-               hfsplus_inode_read_fork(inode, HFSPLUS_IS_DATA(inode) ?
-                                       &file->data_fork : &file->rsrc_fork);
+               hfsplus_inode_read_fork(inode, HFSPLUS_IS_RSRC(inode) ?
+                                       &file->rsrc_fork : &file->data_fork);
                hfsplus_get_perms(inode, &file->permissions, 0);
                inode->i_nlink = 1;
                if (S_ISREG(inode->i_mode)) {
                        if (file->permissions.dev)
-                               inode->i_nlink = be32_to_cpu(file->permissions.dev);
+                               inode->i_nlink =
+                                       be32_to_cpu(file->permissions.dev);
                        inode->i_op = &hfsplus_file_inode_operations;
                        inode->i_fop = &hfsplus_file_operations;
                        inode->i_mapping->a_ops = &hfsplus_aops;
@@ -578,7 +599,9 @@ int hfsplus_cat_write_inode(struct inode *inode)
                                        sizeof(struct hfsplus_cat_file));
                hfsplus_inode_write_fork(inode, &file->data_fork);
                hfsplus_cat_set_perms(inode, &file->permissions);
-               if ((file->permissions.rootflags | file->permissions.userflags) & HFSPLUS_FLG_IMMUTABLE)
+               if (HFSPLUS_FLG_IMMUTABLE &
+                               (file->permissions.rootflags |
+                                       file->permissions.userflags))
                        file->flags |= cpu_to_be16(HFSPLUS_FILE_LOCKED);
                else
                        file->flags &= cpu_to_be16(~HFSPLUS_FILE_LOCKED);
@@ -588,6 +611,8 @@ int hfsplus_cat_write_inode(struct inode *inode)
                hfs_bnode_write(fd.bnode, &entry, fd.entryoffset,
                                         sizeof(struct hfsplus_cat_file));
        }
+
+       set_bit(HFSPLUS_I_CAT_DIRTY, &HFSPLUS_I(inode)->flags);
 out:
        hfs_find_exit(&fd);
        return 0;
index 40a85a3ded6efe6a0a17d08fe2b068ba6b4e369a..508ce662ce122b0b5bea34f6f6260ae22ef0a512 100644 (file)
@@ -28,7 +28,7 @@ static int hfsplus_ioctl_getflags(struct file *file, int __user *user_flags)
 
        if (inode->i_flags & S_IMMUTABLE)
                flags |= FS_IMMUTABLE_FL;
-       if (inode->i_flags |= S_APPEND)
+       if (inode->i_flags & S_APPEND)
                flags |= FS_APPEND_FL;
        if (hip->userflags & HFSPLUS_FLG_NODUMP)
                flags |= FS_NODUMP_FL;
@@ -147,9 +147,11 @@ int hfsplus_setxattr(struct dentry *dentry, const char *name,
                        res = -ERANGE;
        } else
                res = -EOPNOTSUPP;
-       if (!res)
+       if (!res) {
                hfs_bnode_write(fd.bnode, &entry, fd.entryoffset,
                                sizeof(struct hfsplus_cat_file));
+               hfsplus_mark_inode_dirty(inode, HFSPLUS_I_CAT_DIRTY);
+       }
 out:
        hfs_find_exit(&fd);
        return res;
index f9ab276a4d8de9e15d2acf49a358da1a9ff10fe6..bb62a5882147e7c800f21b6173126a6dfa51e1f3 100644 (file)
@@ -23,6 +23,7 @@ enum {
        opt_umask, opt_uid, opt_gid,
        opt_part, opt_session, opt_nls,
        opt_nodecompose, opt_decompose,
+       opt_barrier, opt_nobarrier,
        opt_force, opt_err
 };
 
@@ -37,6 +38,8 @@ static const match_table_t tokens = {
        { opt_nls, "nls=%s" },
        { opt_decompose, "decompose" },
        { opt_nodecompose, "nodecompose" },
+       { opt_barrier, "barrier" },
+       { opt_nobarrier, "nobarrier" },
        { opt_force, "force" },
        { opt_err, NULL }
 };
@@ -65,6 +68,32 @@ static inline int match_fourchar(substring_t *arg, u32 *result)
        return 0;
 }
 
+int hfsplus_parse_options_remount(char *input, int *force)
+{
+       char *p;
+       substring_t args[MAX_OPT_ARGS];
+       int token;
+
+       if (!input)
+               return 0;
+
+       while ((p = strsep(&input, ",")) != NULL) {
+               if (!*p)
+                       continue;
+
+               token = match_token(p, tokens, args);
+               switch (token) {
+               case opt_force:
+                       *force = 1;
+                       break;
+               default:
+                       break;
+               }
+       }
+
+       return 1;
+}
+
 /* Parse options from mount. Returns 0 on failure */
 /* input is the options passed to mount() as a string */
 int hfsplus_parse_options(char *input, struct hfsplus_sb_info *sbi)
@@ -136,7 +165,9 @@ int hfsplus_parse_options(char *input, struct hfsplus_sb_info *sbi)
                        if (p)
                                sbi->nls = load_nls(p);
                        if (!sbi->nls) {
-                               printk(KERN_ERR "hfs: unable to load nls mapping \"%s\"\n", p);
+                               printk(KERN_ERR "hfs: unable to load "
+                                               "nls mapping \"%s\"\n",
+                                       p);
                                kfree(p);
                                return 0;
                        }
@@ -148,6 +179,12 @@ int hfsplus_parse_options(char *input, struct hfsplus_sb_info *sbi)
                case opt_nodecompose:
                        set_bit(HFSPLUS_SB_NODECOMPOSE, &sbi->flags);
                        break;
+               case opt_barrier:
+                       clear_bit(HFSPLUS_SB_NOBARRIER, &sbi->flags);
+                       break;
+               case opt_nobarrier:
+                       set_bit(HFSPLUS_SB_NOBARRIER, &sbi->flags);
+                       break;
                case opt_force:
                        set_bit(HFSPLUS_SB_FORCE, &sbi->flags);
                        break;
@@ -177,7 +214,8 @@ int hfsplus_show_options(struct seq_file *seq, struct vfsmount *mnt)
                seq_printf(seq, ",creator=%.4s", (char *)&sbi->creator);
        if (sbi->type != HFSPLUS_DEF_CR_TYPE)
                seq_printf(seq, ",type=%.4s", (char *)&sbi->type);
-       seq_printf(seq, ",umask=%o,uid=%u,gid=%u", sbi->umask, sbi->uid, sbi->gid);
+       seq_printf(seq, ",umask=%o,uid=%u,gid=%u", sbi->umask,
+               sbi->uid, sbi->gid);
        if (sbi->part >= 0)
                seq_printf(seq, ",part=%u", sbi->part);
        if (sbi->session >= 0)
@@ -186,5 +224,7 @@ int hfsplus_show_options(struct seq_file *seq, struct vfsmount *mnt)
                seq_printf(seq, ",nls=%s", sbi->nls->charset);
        if (test_bit(HFSPLUS_SB_NODECOMPOSE, &sbi->flags))
                seq_printf(seq, ",nodecompose");
+       if (test_bit(HFSPLUS_SB_NOBARRIER, &sbi->flags))
+               seq_printf(seq, ",nobarrier");
        return 0;
 }
index 208b16c645cc234c6f5ce1b15fbd5b49ba802ee8..d66ad113b1cc4e265f8af88f0ac50536b9ca6743 100644 (file)
@@ -2,7 +2,8 @@
  * linux/fs/hfsplus/part_tbl.c
  *
  * Copyright (C) 1996-1997  Paul H. Hargrove
- * This file may be distributed under the terms of the GNU General Public License.
+ * This file may be distributed under the terms of
+ * the GNU General Public License.
  *
  * Original code to handle the new style Mac partition table based on
  * a patch contributed by Holger Schemel (aeglos@valinor.owl.de).
@@ -13,6 +14,7 @@
  *
  */
 
+#include <linux/slab.h>
 #include "hfsplus_fs.h"
 
 /* offsets to various blocks */
@@ -58,77 +60,94 @@ struct new_pmap {
  */
 struct old_pmap {
        __be16          pdSig;  /* Signature bytes */
-       struct  old_pmap_entry {
+       struct old_pmap_entry {
                __be32  pdStart;
                __be32  pdSize;
                __be32  pdFSID;
        }       pdEntry[42];
 } __packed;
 
+static int hfs_parse_old_pmap(struct super_block *sb, struct old_pmap *pm,
+               sector_t *part_start, sector_t *part_size)
+{
+       struct hfsplus_sb_info *sbi = HFSPLUS_SB(sb);
+       int i;
+
+       for (i = 0; i < 42; i++) {
+               struct old_pmap_entry *p = &pm->pdEntry[i];
+
+               if (p->pdStart && p->pdSize &&
+                   p->pdFSID == cpu_to_be32(0x54465331)/*"TFS1"*/ &&
+                   (sbi->part < 0 || sbi->part == i)) {
+                       *part_start += be32_to_cpu(p->pdStart);
+                       *part_size = be32_to_cpu(p->pdSize);
+                       return 0;
+               }
+       }
+
+       return -ENOENT;
+}
+
+static int hfs_parse_new_pmap(struct super_block *sb, struct new_pmap *pm,
+               sector_t *part_start, sector_t *part_size)
+{
+       struct hfsplus_sb_info *sbi = HFSPLUS_SB(sb);
+       int size = be32_to_cpu(pm->pmMapBlkCnt);
+       int res;
+       int i = 0;
+
+       do {
+               if (!memcmp(pm->pmPartType, "Apple_HFS", 9) &&
+                   (sbi->part < 0 || sbi->part == i)) {
+                       *part_start += be32_to_cpu(pm->pmPyPartStart);
+                       *part_size = be32_to_cpu(pm->pmPartBlkCnt);
+                       return 0;
+               }
+
+               if (++i >= size)
+                       return -ENOENT;
+
+               res = hfsplus_submit_bio(sb->s_bdev,
+                                        *part_start + HFS_PMAP_BLK + i,
+                                        pm, READ);
+               if (res)
+                       return res;
+       } while (pm->pmSig == cpu_to_be16(HFS_NEW_PMAP_MAGIC));
+
+       return -ENOENT;
+}
+
 /*
- * hfs_part_find()
- *
- * Parse the partition map looking for the
- * start and length of the 'part'th HFS partition.
+ * Parse the partition map looking for the start and length of a
+ * HFS/HFS+ partition.
  */
 int hfs_part_find(struct super_block *sb,
-                 sector_t *part_start, sector_t *part_size)
+               sector_t *part_start, sector_t *part_size)
 {
-       struct hfsplus_sb_info *sbi = HFSPLUS_SB(sb);
-       struct buffer_head *bh;
-       __be16 *data;
-       int i, size, res;
+       void *data;
+       int res;
+
+       data = kmalloc(HFSPLUS_SECTOR_SIZE, GFP_KERNEL);
+       if (!data)
+               return -ENOMEM;
 
-       res = -ENOENT;
-       bh = sb_bread512(sb, *part_start + HFS_PMAP_BLK, data);
-       if (!bh)
-               return -EIO;
+       res = hfsplus_submit_bio(sb->s_bdev, *part_start + HFS_PMAP_BLK,
+                                data, READ);
+       if (res)
+               return res;
 
-       switch (be16_to_cpu(*data)) {
+       switch (be16_to_cpu(*((__be16 *)data))) {
        case HFS_OLD_PMAP_MAGIC:
-         {
-               struct old_pmap *pm;
-               struct old_pmap_entry *p;
-
-               pm = (struct old_pmap *)bh->b_data;
-               p = pm->pdEntry;
-               size = 42;
-               for (i = 0; i < size; p++, i++) {
-                       if (p->pdStart && p->pdSize &&
-                           p->pdFSID == cpu_to_be32(0x54465331)/*"TFS1"*/ &&
-                           (sbi->part < 0 || sbi->part == i)) {
-                               *part_start += be32_to_cpu(p->pdStart);
-                               *part_size = be32_to_cpu(p->pdSize);
-                               res = 0;
-                       }
-               }
+               res = hfs_parse_old_pmap(sb, data, part_start, part_size);
                break;
-         }
        case HFS_NEW_PMAP_MAGIC:
-         {
-               struct new_pmap *pm;
-
-               pm = (struct new_pmap *)bh->b_data;
-               size = be32_to_cpu(pm->pmMapBlkCnt);
-               for (i = 0; i < size;) {
-                       if (!memcmp(pm->pmPartType,"Apple_HFS", 9) &&
-                           (sbi->part < 0 || sbi->part == i)) {
-                               *part_start += be32_to_cpu(pm->pmPyPartStart);
-                               *part_size = be32_to_cpu(pm->pmPartBlkCnt);
-                               res = 0;
-                               break;
-                       }
-                       brelse(bh);
-                       bh = sb_bread512(sb, *part_start + HFS_PMAP_BLK + ++i, pm);
-                       if (!bh)
-                               return -EIO;
-                       if (pm->pmSig != cpu_to_be16(HFS_NEW_PMAP_MAGIC))
-                               break;
-               }
+               res = hfs_parse_new_pmap(sb, data, part_start, part_size);
+               break;
+       default:
+               res = -ENOENT;
                break;
-         }
        }
-       brelse(bh);
 
+       kfree(data);
        return res;
 }
index ddf712e4700e278ec43ad7c94be6fe51c9ef8a3b..6ee6ad20acf25128da6524fab5675d97eb07b61f 100644 (file)
@@ -10,6 +10,7 @@
 #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/pagemap.h>
+#include <linux/blkdev.h>
 #include <linux/fs.h>
 #include <linux/slab.h>
 #include <linux/vfs.h>
@@ -66,6 +67,7 @@ struct inode *hfsplus_iget(struct super_block *sb, unsigned long ino)
        INIT_LIST_HEAD(&HFSPLUS_I(inode)->open_dir_list);
        mutex_init(&HFSPLUS_I(inode)->extents_lock);
        HFSPLUS_I(inode)->flags = 0;
+       HFSPLUS_I(inode)->extent_state = 0;
        HFSPLUS_I(inode)->rsrc_inode = NULL;
        atomic_set(&HFSPLUS_I(inode)->opencnt, 0);
 
@@ -157,45 +159,65 @@ int hfsplus_sync_fs(struct super_block *sb, int wait)
 {
        struct hfsplus_sb_info *sbi = HFSPLUS_SB(sb);
        struct hfsplus_vh *vhdr = sbi->s_vhdr;
+       int write_backup = 0;
+       int error, error2;
+
+       if (!wait)
+               return 0;
 
        dprint(DBG_SUPER, "hfsplus_write_super\n");
 
-       mutex_lock(&sbi->vh_mutex);
-       mutex_lock(&sbi->alloc_mutex);
        sb->s_dirt = 0;
 
+       /*
+        * Explicitly write out the special metadata inodes.
+        *
+        * While these special inodes are marked as hashed and written
+        * out peridocically by the flusher threads we redirty them
+        * during writeout of normal inodes, and thus the life lock
+        * prevents us from getting the latest state to disk.
+        */
+       error = filemap_write_and_wait(sbi->cat_tree->inode->i_mapping);
+       error2 = filemap_write_and_wait(sbi->ext_tree->inode->i_mapping);
+       if (!error)
+               error = error2;
+       error2 = filemap_write_and_wait(sbi->alloc_file->i_mapping);
+       if (!error)
+               error = error2;
+
+       mutex_lock(&sbi->vh_mutex);
+       mutex_lock(&sbi->alloc_mutex);
        vhdr->free_blocks = cpu_to_be32(sbi->free_blocks);
        vhdr->next_cnid = cpu_to_be32(sbi->next_cnid);
        vhdr->folder_count = cpu_to_be32(sbi->folder_count);
        vhdr->file_count = cpu_to_be32(sbi->file_count);
 
-       mark_buffer_dirty(sbi->s_vhbh);
        if (test_and_clear_bit(HFSPLUS_SB_WRITEBACKUP, &sbi->flags)) {
-               if (sbi->sect_count) {
-                       struct buffer_head *bh;
-                       u32 block, offset;
-
-                       block = sbi->blockoffset;
-                       block += (sbi->sect_count - 2) >> (sb->s_blocksize_bits - 9);
-                       offset = ((sbi->sect_count - 2) << 9) & (sb->s_blocksize - 1);
-                       printk(KERN_DEBUG "hfs: backup: %u,%u,%u,%u\n",
-                                         sbi->blockoffset, sbi->sect_count,
-                                         block, offset);
-                       bh = sb_bread(sb, block);
-                       if (bh) {
-                               vhdr = (struct hfsplus_vh *)(bh->b_data + offset);
-                               if (be16_to_cpu(vhdr->signature) == HFSPLUS_VOLHEAD_SIG) {
-                                       memcpy(vhdr, sbi->s_vhdr, sizeof(*vhdr));
-                                       mark_buffer_dirty(bh);
-                                       brelse(bh);
-                               } else
-                                       printk(KERN_WARNING "hfs: backup not found!\n");
-                       }
-               }
+               memcpy(sbi->s_backup_vhdr, sbi->s_vhdr, sizeof(*sbi->s_vhdr));
+               write_backup = 1;
        }
+
+       error2 = hfsplus_submit_bio(sb->s_bdev,
+                                  sbi->part_start + HFSPLUS_VOLHEAD_SECTOR,
+                                  sbi->s_vhdr, WRITE_SYNC);
+       if (!error)
+               error = error2;
+       if (!write_backup)
+               goto out;
+
+       error2 = hfsplus_submit_bio(sb->s_bdev,
+                                 sbi->part_start + sbi->sect_count - 2,
+                                 sbi->s_backup_vhdr, WRITE_SYNC);
+       if (!error)
+               error2 = error;
+out:
        mutex_unlock(&sbi->alloc_mutex);
        mutex_unlock(&sbi->vh_mutex);
-       return 0;
+
+       if (!test_bit(HFSPLUS_SB_NOBARRIER, &sbi->flags))
+               blkdev_issue_flush(sb->s_bdev, GFP_KERNEL, NULL);
+
+       return error;
 }
 
 static void hfsplus_write_super(struct super_block *sb)
@@ -215,23 +237,22 @@ static void hfsplus_put_super(struct super_block *sb)
        if (!sb->s_fs_info)
                return;
 
-       if (sb->s_dirt)
-               hfsplus_write_super(sb);
        if (!(sb->s_flags & MS_RDONLY) && sbi->s_vhdr) {
                struct hfsplus_vh *vhdr = sbi->s_vhdr;
 
                vhdr->modify_date = hfsp_now2mt();
                vhdr->attributes |= cpu_to_be32(HFSPLUS_VOL_UNMNT);
                vhdr->attributes &= cpu_to_be32(~HFSPLUS_VOL_INCNSTNT);
-               mark_buffer_dirty(sbi->s_vhbh);
-               sync_dirty_buffer(sbi->s_vhbh);
+
+               hfsplus_sync_fs(sb, 1);
        }
 
        hfs_btree_close(sbi->cat_tree);
        hfs_btree_close(sbi->ext_tree);
        iput(sbi->alloc_file);
        iput(sbi->hidden_dir);
-       brelse(sbi->s_vhbh);
+       kfree(sbi->s_vhdr);
+       kfree(sbi->s_backup_vhdr);
        unload_nls(sbi->nls);
        kfree(sb->s_fs_info);
        sb->s_fs_info = NULL;
@@ -263,26 +284,31 @@ static int hfsplus_remount(struct super_block *sb, int *flags, char *data)
                return 0;
        if (!(*flags & MS_RDONLY)) {
                struct hfsplus_vh *vhdr = HFSPLUS_SB(sb)->s_vhdr;
-               struct hfsplus_sb_info sbi;
+               int force = 0;
 
-               memset(&sbi, 0, sizeof(struct hfsplus_sb_info));
-               sbi.nls = HFSPLUS_SB(sb)->nls;
-               if (!hfsplus_parse_options(data, &sbi))
+               if (!hfsplus_parse_options_remount(data, &force))
                        return -EINVAL;
 
                if (!(vhdr->attributes & cpu_to_be32(HFSPLUS_VOL_UNMNT))) {
-                       printk(KERN_WARNING "hfs: filesystem was not cleanly unmounted, "
-                              "running fsck.hfsplus is recommended.  leaving read-only.\n");
+                       printk(KERN_WARNING "hfs: filesystem was "
+                                       "not cleanly unmounted, "
+                                       "running fsck.hfsplus is recommended.  "
+                                       "leaving read-only.\n");
                        sb->s_flags |= MS_RDONLY;
                        *flags |= MS_RDONLY;
-               } else if (test_bit(HFSPLUS_SB_FORCE, &sbi.flags)) {
+               } else if (force) {
                        /* nothing */
-               } else if (vhdr->attributes & cpu_to_be32(HFSPLUS_VOL_SOFTLOCK)) {
-                       printk(KERN_WARNING "hfs: filesystem is marked locked, leaving read-only.\n");
+               } else if (vhdr->attributes &
+                               cpu_to_be32(HFSPLUS_VOL_SOFTLOCK)) {
+                       printk(KERN_WARNING "hfs: filesystem is marked locked, "
+                                       "leaving read-only.\n");
                        sb->s_flags |= MS_RDONLY;
                        *flags |= MS_RDONLY;
-               } else if (vhdr->attributes & cpu_to_be32(HFSPLUS_VOL_JOURNALED)) {
-                       printk(KERN_WARNING "hfs: filesystem is marked journaled, leaving read-only.\n");
+               } else if (vhdr->attributes &
+                               cpu_to_be32(HFSPLUS_VOL_JOURNALED)) {
+                       printk(KERN_WARNING "hfs: filesystem is "
+                                       "marked journaled, "
+                                       "leaving read-only.\n");
                        sb->s_flags |= MS_RDONLY;
                        *flags |= MS_RDONLY;
                }
@@ -372,17 +398,22 @@ static int hfsplus_fill_super(struct super_block *sb, void *data, int silent)
        sb->s_maxbytes = MAX_LFS_FILESIZE;
 
        if (!(vhdr->attributes & cpu_to_be32(HFSPLUS_VOL_UNMNT))) {
-               printk(KERN_WARNING "hfs: Filesystem was not cleanly unmounted, "
-                      "running fsck.hfsplus is recommended.  mounting read-only.\n");
+               printk(KERN_WARNING "hfs: Filesystem was "
+                               "not cleanly unmounted, "
+                               "running fsck.hfsplus is recommended.  "
+                               "mounting read-only.\n");
                sb->s_flags |= MS_RDONLY;
        } else if (test_and_clear_bit(HFSPLUS_SB_FORCE, &sbi->flags)) {
                /* nothing */
        } else if (vhdr->attributes & cpu_to_be32(HFSPLUS_VOL_SOFTLOCK)) {
                printk(KERN_WARNING "hfs: Filesystem is marked locked, mounting read-only.\n");
                sb->s_flags |= MS_RDONLY;
-       } else if ((vhdr->attributes & cpu_to_be32(HFSPLUS_VOL_JOURNALED)) && !(sb->s_flags & MS_RDONLY)) {
-               printk(KERN_WARNING "hfs: write access to a journaled filesystem is not supported, "
-                      "use the force option at your own risk, mounting read-only.\n");
+       } else if ((vhdr->attributes & cpu_to_be32(HFSPLUS_VOL_JOURNALED)) &&
+                       !(sb->s_flags & MS_RDONLY)) {
+               printk(KERN_WARNING "hfs: write access to "
+                               "a journaled filesystem is not supported, "
+                               "use the force option at your own risk, "
+                               "mounting read-only.\n");
                sb->s_flags |= MS_RDONLY;
        }
 
@@ -449,19 +480,16 @@ static int hfsplus_fill_super(struct super_block *sb, void *data, int silent)
        be32_add_cpu(&vhdr->write_count, 1);
        vhdr->attributes &= cpu_to_be32(~HFSPLUS_VOL_UNMNT);
        vhdr->attributes |= cpu_to_be32(HFSPLUS_VOL_INCNSTNT);
-       mark_buffer_dirty(sbi->s_vhbh);
-       sync_dirty_buffer(sbi->s_vhbh);
+       hfsplus_sync_fs(sb, 1);
 
        if (!sbi->hidden_dir) {
-               printk(KERN_DEBUG "hfs: create hidden dir...\n");
-
                mutex_lock(&sbi->vh_mutex);
                sbi->hidden_dir = hfsplus_new_inode(sb, S_IFDIR);
                hfsplus_create_cat(sbi->hidden_dir->i_ino, sb->s_root->d_inode,
                                   &str, sbi->hidden_dir);
                mutex_unlock(&sbi->vh_mutex);
 
-               mark_inode_dirty(sbi->hidden_dir);
+               hfsplus_mark_inode_dirty(sbi->hidden_dir, HFSPLUS_I_CAT_DIRTY);
        }
 out:
        unload_nls(sbi->nls);
index d800aa0f2c80d9324018cb89ff9dfeb897e6b048..a3f0bfcc881ef588d0d95e9d9fbd46ad61a32c4e 100644 (file)
 /* Returns folded char, or 0 if ignorable */
 static inline u16 case_fold(u16 c)
 {
-        u16 tmp;
-
-        tmp = hfsplus_case_fold_table[c >> 8];
-        if (tmp)
-                tmp = hfsplus_case_fold_table[tmp + (c & 0xff)];
-        else
-                tmp = c;
-        return tmp;
+       u16 tmp;
+
+       tmp = hfsplus_case_fold_table[c >> 8];
+       if (tmp)
+               tmp = hfsplus_case_fold_table[tmp + (c & 0xff)];
+       else
+               tmp = c;
+       return tmp;
 }
 
 /* Compare unicode strings, return values like normal strcmp */
@@ -118,7 +118,9 @@ static u16 *hfsplus_compose_lookup(u16 *p, u16 cc)
        return NULL;
 }
 
-int hfsplus_uni2asc(struct super_block *sb, const struct hfsplus_unistr *ustr, char *astr, int *len_p)
+int hfsplus_uni2asc(struct super_block *sb,
+               const struct hfsplus_unistr *ustr,
+               char *astr, int *len_p)
 {
        const hfsplus_unichr *ip;
        struct nls_table *nls = HFSPLUS_SB(sb)->nls;
@@ -171,7 +173,8 @@ int hfsplus_uni2asc(struct super_block *sb, const struct hfsplus_unistr *ustr, c
                                goto same;
                        c1 = be16_to_cpu(*ip);
                        if (likely(compose))
-                               ce1 = hfsplus_compose_lookup(hfsplus_compose_table, c1);
+                               ce1 = hfsplus_compose_lookup(
+                                       hfsplus_compose_table, c1);
                        if (ce1)
                                break;
                        switch (c0) {
@@ -199,7 +202,8 @@ int hfsplus_uni2asc(struct super_block *sb, const struct hfsplus_unistr *ustr, c
                if (ce2) {
                        i = 1;
                        while (i < ustrlen) {
-                               ce1 = hfsplus_compose_lookup(ce2, be16_to_cpu(ip[i]));
+                               ce1 = hfsplus_compose_lookup(ce2,
+                                       be16_to_cpu(ip[i]));
                                if (!ce1)
                                        break;
                                i++;
@@ -211,7 +215,7 @@ int hfsplus_uni2asc(struct super_block *sb, const struct hfsplus_unistr *ustr, c
                                goto done;
                        }
                }
-       same:
+same:
                switch (c0) {
                case 0:
                        cc = 0x2400;
@@ -222,7 +226,7 @@ int hfsplus_uni2asc(struct super_block *sb, const struct hfsplus_unistr *ustr, c
                default:
                        cc = c0;
                }
-       done:
+done:
                res = nls->uni2char(cc, op, len);
                if (res < 0) {
                        if (res == -ENAMETOOLONG)
@@ -392,7 +396,9 @@ int hfsplus_compare_dentry(const struct dentry *parent,
                        astr1 += size;
                        len1 -= size;
 
-                       if (!decompose || !(dstr1 = decompose_unichar(c, &dsize1))) {
+                       if (decompose)
+                               dstr1 = decompose_unichar(c, &dsize1);
+                       if (!decompose || !dstr1) {
                                c1 = c;
                                dstr1 = &c1;
                                dsize1 = 1;
@@ -404,7 +410,9 @@ int hfsplus_compare_dentry(const struct dentry *parent,
                        astr2 += size;
                        len2 -= size;
 
-                       if (!decompose || !(dstr2 = decompose_unichar(c, &dsize2))) {
+                       if (decompose)
+                               dstr2 = decompose_unichar(c, &dsize2);
+                       if (!decompose || !dstr2) {
                                c2 = c;
                                dstr2 = &c2;
                                dsize2 = 1;
index 8972c20b3216941a88eb3deffa591d89ea3c114a..196231794f646de0ead6b1e3d6cfc5d29c7ce54d 100644 (file)
@@ -24,6 +24,40 @@ struct hfsplus_wd {
        u16 embed_count;
 };
 
+static void hfsplus_end_io_sync(struct bio *bio, int err)
+{
+       if (err)
+               clear_bit(BIO_UPTODATE, &bio->bi_flags);
+       complete(bio->bi_private);
+}
+
+int hfsplus_submit_bio(struct block_device *bdev, sector_t sector,
+               void *data, int rw)
+{
+       DECLARE_COMPLETION_ONSTACK(wait);
+       struct bio *bio;
+
+       bio = bio_alloc(GFP_NOIO, 1);
+       bio->bi_sector = sector;
+       bio->bi_bdev = bdev;
+       bio->bi_end_io = hfsplus_end_io_sync;
+       bio->bi_private = &wait;
+
+       /*
+        * We always submit one sector at a time, so bio_add_page must not fail.
+        */
+       if (bio_add_page(bio, virt_to_page(data), HFSPLUS_SECTOR_SIZE,
+                        offset_in_page(data)) != HFSPLUS_SECTOR_SIZE)
+               BUG();
+
+       submit_bio(rw, bio);
+       wait_for_completion(&wait);
+
+       if (!bio_flagged(bio, BIO_UPTODATE))
+               return -EIO;
+       return 0;
+}
+
 static int hfsplus_read_mdb(void *bufptr, struct hfsplus_wd *wd)
 {
        u32 extent;
@@ -40,12 +74,14 @@ static int hfsplus_read_mdb(void *bufptr, struct hfsplus_wd *wd)
           !(attrib & HFSP_WRAP_ATTRIB_SPARED))
                return 0;
 
-       wd->ablk_size = be32_to_cpu(*(__be32 *)(bufptr + HFSP_WRAPOFF_ABLKSIZE));
+       wd->ablk_size =
+               be32_to_cpu(*(__be32 *)(bufptr + HFSP_WRAPOFF_ABLKSIZE));
        if (wd->ablk_size < HFSPLUS_SECTOR_SIZE)
                return 0;
        if (wd->ablk_size % HFSPLUS_SECTOR_SIZE)
                return 0;
-       wd->ablk_start = be16_to_cpu(*(__be16 *)(bufptr + HFSP_WRAPOFF_ABLKSTART));
+       wd->ablk_start =
+               be16_to_cpu(*(__be16 *)(bufptr + HFSP_WRAPOFF_ABLKSTART));
 
        extent = get_unaligned_be32(bufptr + HFSP_WRAPOFF_EMBEDEXT);
        wd->embed_start = (extent >> 16) & 0xFFFF;
@@ -68,7 +104,8 @@ static int hfsplus_get_last_session(struct super_block *sb,
        if (HFSPLUS_SB(sb)->session >= 0) {
                te.cdte_track = HFSPLUS_SB(sb)->session;
                te.cdte_format = CDROM_LBA;
-               res = ioctl_by_bdev(sb->s_bdev, CDROMREADTOCENTRY, (unsigned long)&te);
+               res = ioctl_by_bdev(sb->s_bdev,
+                       CDROMREADTOCENTRY, (unsigned long)&te);
                if (!res && (te.cdte_ctrl & CDROM_DATA_TRACK) == 4) {
                        *start = (sector_t)te.cdte_addr.lba << 2;
                        return 0;
@@ -77,7 +114,8 @@ static int hfsplus_get_last_session(struct super_block *sb,
                return -EINVAL;
        }
        ms_info.addr_format = CDROM_LBA;
-       res = ioctl_by_bdev(sb->s_bdev, CDROMMULTISESSION, (unsigned long)&ms_info);
+       res = ioctl_by_bdev(sb->s_bdev, CDROMMULTISESSION,
+               (unsigned long)&ms_info);
        if (!res && ms_info.xa_flag)
                *start = (sector_t)ms_info.addr.lba << 2;
        return 0;
@@ -88,100 +126,112 @@ static int hfsplus_get_last_session(struct super_block *sb,
 int hfsplus_read_wrapper(struct super_block *sb)
 {
        struct hfsplus_sb_info *sbi = HFSPLUS_SB(sb);
-       struct buffer_head *bh;
-       struct hfsplus_vh *vhdr;
        struct hfsplus_wd wd;
        sector_t part_start, part_size;
        u32 blocksize;
+       int error = 0;
 
+       error = -EINVAL;
        blocksize = sb_min_blocksize(sb, HFSPLUS_SECTOR_SIZE);
        if (!blocksize)
-               return -EINVAL;
+               goto out;
 
        if (hfsplus_get_last_session(sb, &part_start, &part_size))
-               return -EINVAL;
+               goto out;
        if ((u64)part_start + part_size > 0x100000000ULL) {
                pr_err("hfs: volumes larger than 2TB are not supported yet\n");
-               return -EINVAL;
+               goto out;
        }
-       while (1) {
-               bh = sb_bread512(sb, part_start + HFSPLUS_VOLHEAD_SECTOR, vhdr);
-               if (!bh)
-                       return -EIO;
-
-               if (vhdr->signature == cpu_to_be16(HFSP_WRAP_MAGIC)) {
-                       if (!hfsplus_read_mdb(vhdr, &wd))
-                               goto error;
-                       wd.ablk_size >>= HFSPLUS_SECTOR_SHIFT;
-                       part_start += wd.ablk_start + wd.embed_start * wd.ablk_size;
-                       part_size = wd.embed_count * wd.ablk_size;
-                       brelse(bh);
-                       bh = sb_bread512(sb, part_start + HFSPLUS_VOLHEAD_SECTOR, vhdr);
-                       if (!bh)
-                               return -EIO;
-               }
-               if (vhdr->signature == cpu_to_be16(HFSPLUS_VOLHEAD_SIG))
-                       break;
-               if (vhdr->signature == cpu_to_be16(HFSPLUS_VOLHEAD_SIGX)) {
-                       set_bit(HFSPLUS_SB_HFSX, &sbi->flags);
-                       break;
-               }
-               brelse(bh);
 
-               /* check for a partition block
+       error = -ENOMEM;
+       sbi->s_vhdr = kmalloc(HFSPLUS_SECTOR_SIZE, GFP_KERNEL);
+       if (!sbi->s_vhdr)
+               goto out;
+       sbi->s_backup_vhdr = kmalloc(HFSPLUS_SECTOR_SIZE, GFP_KERNEL);
+       if (!sbi->s_backup_vhdr)
+               goto out_free_vhdr;
+
+reread:
+       error = hfsplus_submit_bio(sb->s_bdev,
+                                  part_start + HFSPLUS_VOLHEAD_SECTOR,
+                                  sbi->s_vhdr, READ);
+       if (error)
+               goto out_free_backup_vhdr;
+
+       error = -EINVAL;
+       switch (sbi->s_vhdr->signature) {
+       case cpu_to_be16(HFSPLUS_VOLHEAD_SIGX):
+               set_bit(HFSPLUS_SB_HFSX, &sbi->flags);
+               /*FALLTHRU*/
+       case cpu_to_be16(HFSPLUS_VOLHEAD_SIG):
+               break;
+       case cpu_to_be16(HFSP_WRAP_MAGIC):
+               if (!hfsplus_read_mdb(sbi->s_vhdr, &wd))
+                       goto out;
+               wd.ablk_size >>= HFSPLUS_SECTOR_SHIFT;
+               part_start += wd.ablk_start + wd.embed_start * wd.ablk_size;
+               part_size = wd.embed_count * wd.ablk_size;
+               goto reread;
+       default:
+               /*
+                * Check for a partition block.
+                *
                 * (should do this only for cdrom/loop though)
                 */
                if (hfs_part_find(sb, &part_start, &part_size))
-                       return -EINVAL;
+                       goto out;
+               goto reread;
+       }
+
+       error = hfsplus_submit_bio(sb->s_bdev,
+                                  part_start + part_size - 2,
+                                  sbi->s_backup_vhdr, READ);
+       if (error)
+               goto out_free_backup_vhdr;
+
+       error = -EINVAL;
+       if (sbi->s_backup_vhdr->signature != sbi->s_vhdr->signature) {
+               printk(KERN_WARNING
+                       "hfs: invalid secondary volume header\n");
+               goto out_free_backup_vhdr;
        }
 
-       blocksize = be32_to_cpu(vhdr->blocksize);
-       brelse(bh);
+       blocksize = be32_to_cpu(sbi->s_vhdr->blocksize);
 
-       /* block size must be at least as large as a sector
-        * and a multiple of 2
+       /*
+        * Block size must be at least as large as a sector and a multiple of 2.
         */
-       if (blocksize < HFSPLUS_SECTOR_SIZE ||
-           ((blocksize - 1) & blocksize))
-               return -EINVAL;
+       if (blocksize < HFSPLUS_SECTOR_SIZE || ((blocksize - 1) & blocksize))
+               goto out_free_backup_vhdr;
        sbi->alloc_blksz = blocksize;
        sbi->alloc_blksz_shift = 0;
        while ((blocksize >>= 1) != 0)
                sbi->alloc_blksz_shift++;
        blocksize = min(sbi->alloc_blksz, (u32)PAGE_SIZE);
 
-       /* align block size to block offset */
+       /*
+        * Align block size to block offset.
+        */
        while (part_start & ((blocksize >> HFSPLUS_SECTOR_SHIFT) - 1))
                blocksize >>= 1;
 
        if (sb_set_blocksize(sb, blocksize) != blocksize) {
-               printk(KERN_ERR "hfs: unable to set blocksize to %u!\n", blocksize);
-               return -EINVAL;
+               printk(KERN_ERR "hfs: unable to set blocksize to %u!\n",
+                       blocksize);
+               goto out_free_backup_vhdr;
        }
 
        sbi->blockoffset =
                part_start >> (sb->s_blocksize_bits - HFSPLUS_SECTOR_SHIFT);
+       sbi->part_start = part_start;
        sbi->sect_count = part_size;
        sbi->fs_shift = sbi->alloc_blksz_shift - sb->s_blocksize_bits;
-
-       bh = sb_bread512(sb, part_start + HFSPLUS_VOLHEAD_SECTOR, vhdr);
-       if (!bh)
-               return -EIO;
-
-       /* should still be the same... */
-       if (test_bit(HFSPLUS_SB_HFSX, &sbi->flags)) {
-               if (vhdr->signature != cpu_to_be16(HFSPLUS_VOLHEAD_SIGX))
-                       goto error;
-       } else {
-               if (vhdr->signature != cpu_to_be16(HFSPLUS_VOLHEAD_SIG))
-                       goto error;
-       }
-
-       sbi->s_vhbh = bh;
-       sbi->s_vhdr = vhdr;
-
        return 0;
- error:
-       brelse(bh);
-       return -EINVAL;
+
+out_free_backup_vhdr:
+       kfree(sbi->s_backup_vhdr);
+out_free_vhdr:
+       kfree(sbi->s_vhdr);
+out:
+       return error;
 }