Merge git://git.kernel.org/pub/scm/linux/kernel/git/steve/gfs2-2.6-nmw
[pandora-kernel.git] / fs / hfsplus / super.c
index bd09ea2..9a88d75 100644 (file)
@@ -89,63 +89,57 @@ struct inode *hfsplus_iget(struct super_block *sb, unsigned long ino)
        return inode;
 }
 
-static int hfsplus_write_inode(struct inode *inode,
-               struct writeback_control *wbc)
+static int hfsplus_system_write_inode(struct inode *inode)
 {
        struct hfsplus_sb_info *sbi = HFSPLUS_SB(inode->i_sb);
-       struct hfsplus_vh *vhdr;
-       int ret = 0;
+       struct hfsplus_vh *vhdr = sbi->s_vhdr;
+       struct hfsplus_fork_raw *fork;
+       struct hfs_btree *tree = NULL;
 
-       dprint(DBG_INODE, "hfsplus_write_inode: %lu\n", inode->i_ino);
-       hfsplus_ext_write_extent(inode);
-       if (inode->i_ino >= HFSPLUS_FIRSTUSER_CNID) {
-               return hfsplus_cat_write_inode(inode);
-       }
-       vhdr = sbi->s_vhdr;
        switch (inode->i_ino) {
-       case HFSPLUS_ROOT_CNID:
-               ret = hfsplus_cat_write_inode(inode);
-               break;
        case HFSPLUS_EXT_CNID:
-               if (vhdr->ext_file.total_size != cpu_to_be64(inode->i_size)) {
-                       sbi->flags |= HFSPLUS_SB_WRITEBACKUP;
-                       inode->i_sb->s_dirt = 1;
-               }
-               hfsplus_inode_write_fork(inode, &vhdr->ext_file);
-               hfs_btree_write(sbi->ext_tree);
+               fork = &vhdr->ext_file;
+               tree = sbi->ext_tree;
                break;
        case HFSPLUS_CAT_CNID:
-               if (vhdr->cat_file.total_size != cpu_to_be64(inode->i_size)) {
-                       sbi->flags |= HFSPLUS_SB_WRITEBACKUP;
-                       inode->i_sb->s_dirt = 1;
-               }
-               hfsplus_inode_write_fork(inode, &vhdr->cat_file);
-               hfs_btree_write(sbi->cat_tree);
+               fork = &vhdr->cat_file;
+               tree = sbi->cat_tree;
                break;
        case HFSPLUS_ALLOC_CNID:
-               if (vhdr->alloc_file.total_size != cpu_to_be64(inode->i_size)) {
-                       sbi->flags |= HFSPLUS_SB_WRITEBACKUP;
-                       inode->i_sb->s_dirt = 1;
-               }
-               hfsplus_inode_write_fork(inode, &vhdr->alloc_file);
+               fork = &vhdr->alloc_file;
                break;
        case HFSPLUS_START_CNID:
-               if (vhdr->start_file.total_size != cpu_to_be64(inode->i_size)) {
-                       sbi->flags |= HFSPLUS_SB_WRITEBACKUP;
-                       inode->i_sb->s_dirt = 1;
-               }
-               hfsplus_inode_write_fork(inode, &vhdr->start_file);
+               fork = &vhdr->start_file;
                break;
        case HFSPLUS_ATTR_CNID:
-               if (vhdr->attr_file.total_size != cpu_to_be64(inode->i_size)) {
-                       sbi->flags |= HFSPLUS_SB_WRITEBACKUP;
-                       inode->i_sb->s_dirt = 1;
-               }
-               hfsplus_inode_write_fork(inode, &vhdr->attr_file);
-               hfs_btree_write(sbi->attr_tree);
-               break;
+               fork = &vhdr->attr_file;
+               tree = sbi->attr_tree;
+       default:
+               return -EIO;
        }
-       return ret;
+
+       if (fork->total_size != cpu_to_be64(inode->i_size)) {
+               set_bit(HFSPLUS_SB_WRITEBACKUP, &sbi->flags);
+               inode->i_sb->s_dirt = 1;
+       }
+       hfsplus_inode_write_fork(inode, fork);
+       if (tree)
+               hfs_btree_write(tree);
+       return 0;
+}
+
+static int hfsplus_write_inode(struct inode *inode,
+               struct writeback_control *wbc)
+{
+       dprint(DBG_INODE, "hfsplus_write_inode: %lu\n", inode->i_ino);
+
+       hfsplus_ext_write_extent(inode);
+
+       if (inode->i_ino >= HFSPLUS_FIRSTUSER_CNID ||
+           inode->i_ino == HFSPLUS_ROOT_CNID)
+               return hfsplus_cat_write_inode(inode);
+       else
+               return hfsplus_system_write_inode(inode);
 }
 
 static void hfsplus_evict_inode(struct inode *inode)
@@ -166,17 +160,17 @@ int hfsplus_sync_fs(struct super_block *sb, int wait)
 
        dprint(DBG_SUPER, "hfsplus_write_super\n");
 
+       mutex_lock(&sbi->vh_mutex);
        mutex_lock(&sbi->alloc_mutex);
        sb->s_dirt = 0;
 
        vhdr->free_blocks = cpu_to_be32(sbi->free_blocks);
-       vhdr->next_alloc = cpu_to_be32(sbi->next_alloc);
        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 (sbi->flags & HFSPLUS_SB_WRITEBACKUP) {
+       if (test_and_clear_bit(HFSPLUS_SB_WRITEBACKUP, &sbi->flags)) {
                if (sbi->sect_count) {
                        struct buffer_head *bh;
                        u32 block, offset;
@@ -198,9 +192,9 @@ int hfsplus_sync_fs(struct super_block *sb, int wait)
                                        printk(KERN_WARNING "hfs: backup not found!\n");
                        }
                }
-               sbi->flags &= ~HFSPLUS_SB_WRITEBACKUP;
        }
        mutex_unlock(&sbi->alloc_mutex);
+       mutex_unlock(&sbi->vh_mutex);
        return 0;
 }
 
@@ -281,7 +275,7 @@ static int hfsplus_remount(struct super_block *sb, int *flags, char *data)
                               "running fsck.hfsplus is recommended.  leaving read-only.\n");
                        sb->s_flags |= MS_RDONLY;
                        *flags |= MS_RDONLY;
-               } else if (sbi.flags & HFSPLUS_SB_FORCE) {
+               } else if (test_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, leaving read-only.\n");
@@ -325,8 +319,8 @@ static int hfsplus_fill_super(struct super_block *sb, void *data, int silent)
                return -ENOMEM;
 
        sb->s_fs_info = sbi;
-       INIT_HLIST_HEAD(&sbi->rsrc_inodes);
        mutex_init(&sbi->alloc_mutex);
+       mutex_init(&sbi->vh_mutex);
        hfsplus_fill_defaults(sbi);
        if (!hfsplus_parse_options(data, sbi)) {
                printk(KERN_ERR "hfs: unable to parse mount options\n");
@@ -361,7 +355,6 @@ static int hfsplus_fill_super(struct super_block *sb, void *data, int silent)
        }
        sbi->total_blocks = be32_to_cpu(vhdr->total_blocks);
        sbi->free_blocks = be32_to_cpu(vhdr->free_blocks);
-       sbi->next_alloc = be32_to_cpu(vhdr->next_alloc);
        sbi->next_cnid = be32_to_cpu(vhdr->next_cnid);
        sbi->file_count = be32_to_cpu(vhdr->file_count);
        sbi->folder_count = be32_to_cpu(vhdr->folder_count);
@@ -382,7 +375,7 @@ static int hfsplus_fill_super(struct super_block *sb, void *data, int silent)
                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 (sbi->flags & HFSPLUS_SB_FORCE) {
+       } 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");
@@ -392,7 +385,6 @@ static int hfsplus_fill_super(struct super_block *sb, void *data, int silent)
                       "use the force option at your own risk, mounting read-only.\n");
                sb->s_flags |= MS_RDONLY;
        }
-       sbi->flags &= ~HFSPLUS_SB_FORCE;
 
        /* Load metadata objects (B*Trees) */
        sbi->ext_tree = hfs_btree_open(sb, HFSPLUS_EXT_CNID);
@@ -462,9 +454,13 @@ static int hfsplus_fill_super(struct super_block *sb, void *data, int silent)
 
        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);
        }
 out: