]> pilppa.org Git - linux-2.6-omap-h63xx.git/blobdiff - fs/btrfs/inode.c
Btrfs: Give each subvol and snapshot their own anonymous devid
[linux-2.6-omap-h63xx.git] / fs / btrfs / inode.c
index 5ca9c0672374a5e6fd6b95fa7ce6a6c8cec42530..7ef79ce86e2514d5b4c496c9cff1628911edfa07 100644 (file)
@@ -184,7 +184,7 @@ static int noinline insert_inline_extent(struct btrfs_trans_handle *trans,
                int i = 0;
                while(compressed_size > 0) {
                        cpage = compressed_pages[i];
-                       cur_size = min(compressed_size,
+                       cur_size = min_t(unsigned long, compressed_size,
                                       PAGE_CACHE_SIZE);
 
                        kaddr = kmap(cpage);
@@ -1808,10 +1808,6 @@ void btrfs_orphan_cleanup(struct btrfs_root *root)
        struct inode *inode;
        int ret = 0, nr_unlink = 0, nr_truncate = 0;
 
-       /* don't do orphan cleanup if the fs is readonly. */
-       if (root->fs_info->sb->s_flags & MS_RDONLY)
-               return;
-
        path = btrfs_alloc_path();
        if (!path)
                return;
@@ -2216,7 +2212,12 @@ static int btrfs_rmdir(struct inode *dir, struct dentry *dentry)
        struct btrfs_trans_handle *trans;
        unsigned long nr = 0;
 
-       if (inode->i_size > BTRFS_EMPTY_DIR_SIZE) {
+       /*
+        * the FIRST_FREE_OBJECTID check makes sure we don't try to rmdir
+        * the root of a subvolume or snapshot
+        */
+       if (inode->i_size > BTRFS_EMPTY_DIR_SIZE ||
+           inode->i_ino == BTRFS_FIRST_FREE_OBJECTID) {
                return -ENOTEMPTY;
        }
 
@@ -3042,15 +3043,14 @@ struct inode *btrfs_iget(struct super_block *s, struct btrfs_key *location,
        return inode;
 }
 
-static struct dentry *btrfs_lookup(struct inode *dir, struct dentry *dentry,
-                                  struct nameidata *nd)
+struct inode *btrfs_lookup_dentry(struct inode *dir, struct dentry *dentry)
 {
        struct inode * inode;
        struct btrfs_inode *bi = BTRFS_I(dir);
        struct btrfs_root *root = bi->root;
        struct btrfs_root *sub_root = root;
        struct btrfs_key location;
-       int ret, new, do_orphan = 0;
+       int ret, new;
 
        if (dentry->d_name.len > BTRFS_NAME_LEN)
                return ERR_PTR(-ENAMETOOLONG);
@@ -3071,17 +3071,21 @@ static struct dentry *btrfs_lookup(struct inode *dir, struct dentry *dentry,
                inode = btrfs_iget(dir->i_sb, &location, sub_root, &new);
                if (IS_ERR(inode))
                        return ERR_CAST(inode);
-
-               /* the inode and parent dir are two different roots */
-               if (new && root != sub_root) {
-                       igrab(inode);
-                       sub_root->inode = inode;
-                       do_orphan = 1;
-               }
        }
+       return inode;
+}
 
-       if (unlikely(do_orphan))
-               btrfs_orphan_cleanup(sub_root);
+static struct dentry *btrfs_lookup(struct inode *dir, struct dentry *dentry,
+                                  struct nameidata *nd)
+{
+       struct inode *inode;
+
+       if (dentry->d_name.len > BTRFS_NAME_LEN)
+               return ERR_PTR(-ENAMETOOLONG);
+
+       inode = btrfs_lookup_dentry(dir, dentry);
+       if (IS_ERR(inode))
+               return ERR_CAST(inode);
 
        return d_splice_alias(inode, dentry);
 }
@@ -3137,7 +3141,6 @@ static int btrfs_real_readdir(struct file *filp, void *dirent,
                        return 0;
                filp->f_pos = 2;
        }
-
        path = btrfs_alloc_path();
        path->reada = 2;
 
@@ -3167,6 +3170,7 @@ static int btrfs_real_readdir(struct file *filp, void *dirent,
                                path->slots[0]++;
                        }
                }
+
                advance = 1;
                item = btrfs_item_nr(leaf, slot);
                btrfs_item_key_to_cpu(leaf, &found_key, slot);
@@ -3202,16 +3206,25 @@ static int btrfs_real_readdir(struct file *filp, void *dirent,
 
                        d_type = btrfs_filetype_table[btrfs_dir_type(leaf, di)];
                        btrfs_dir_item_key_to_cpu(leaf, di, &location);
+
+                       /* is this a reference to our own snapshot? If so
+                        * skip it
+                        */
+                       if (location.type == BTRFS_ROOT_ITEM_KEY &&
+                           location.objectid == root->root_key.objectid) {
+                               over = 0;
+                               goto skip;
+                       }
                        over = filldir(dirent, name_ptr, name_len,
                                       found_key.offset, location.objectid,
                                       d_type);
 
+skip:
                        if (name_ptr != tmp_name)
                                kfree(name_ptr);
 
                        if (over)
                                goto nopos;
-
                        di_len = btrfs_dir_name_len(leaf, di) +
                                 btrfs_dir_data_len(leaf, di) + sizeof(*di);
                        di_cur += di_len;
@@ -3237,7 +3250,7 @@ int btrfs_write_inode(struct inode *inode, int wait)
        struct btrfs_trans_handle *trans;
        int ret = 0;
 
-       if (root->fs_info->closing > 1)
+       if (root->fs_info->btree_inode == inode)
                return 0;
 
        if (wait) {
@@ -3326,8 +3339,7 @@ out:
  * helper to find a free sequence number in a given directory.  This current
  * code is very simple, later versions will do smarter things in the btree
  */
-static int btrfs_set_inode_index(struct inode *dir, struct inode *inode,
-                                u64 *index)
+int btrfs_set_inode_index(struct inode *dir, u64 *index)
 {
        int ret = 0;
 
@@ -3373,7 +3385,7 @@ static struct inode *btrfs_new_inode(struct btrfs_trans_handle *trans,
                return ERR_PTR(-ENOMEM);
 
        if (dir) {
-               ret = btrfs_set_inode_index(dir, inode, index);
+               ret = btrfs_set_inode_index(dir, index);
                if (ret)
                        return ERR_PTR(ret);
        }
@@ -3659,7 +3671,7 @@ static int btrfs_link(struct dentry *old_dentry, struct inode *dir,
        err = btrfs_check_free_space(root, 1, 0);
        if (err)
                goto fail;
-       err = btrfs_set_inode_index(dir, inode, &index);
+       err = btrfs_set_inode_index(dir, &index);
        if (err)
                goto fail;
 
@@ -3812,7 +3824,7 @@ static noinline int uncompress_inline(struct btrfs_path *path,
 
        read_extent_buffer(leaf, tmp, ptr, inline_size);
 
-       max_size = min(PAGE_CACHE_SIZE, max_size);
+       max_size = min_t(unsigned long, PAGE_CACHE_SIZE, max_size);
        ret = btrfs_zlib_decompress(tmp, page, extent_offset,
                                    inline_size, max_size);
        if (ret) {
@@ -4357,13 +4369,13 @@ out:
  * Invalidate a single dcache entry at the root of the filesystem.
  * Needed after creation of snapshot or subvolume.
  */
-void btrfs_invalidate_dcache_root(struct btrfs_root *root, char *name,
+void btrfs_invalidate_dcache_root(struct inode *dir, char *name,
                                  int namelen)
 {
        struct dentry *alias, *entry;
        struct qstr qstr;
 
-       alias = d_find_alias(root->fs_info->sb->s_root->d_inode);
+       alias = d_find_alias(dir);
        if (alias) {
                qstr.name = name;
                qstr.len = namelen;
@@ -4395,7 +4407,6 @@ int btrfs_create_subvol_root(struct btrfs_root *new_root, struct dentry *dentry,
                return PTR_ERR(inode);
        inode->i_op = &btrfs_dir_inode_operations;
        inode->i_fop = &btrfs_dir_file_operations;
-       new_root->inode = inode;
 
        inode->i_nlink = 1;
        btrfs_i_size_write(inode, 0);
@@ -4404,7 +4415,6 @@ int btrfs_create_subvol_root(struct btrfs_root *new_root, struct dentry *dentry,
        if (error)
                return error;
 
-       atomic_inc(&inode->i_count);
        d_instantiate(dentry, inode);
        return 0;
 }
@@ -4542,6 +4552,7 @@ static int btrfs_getattr(struct vfsmount *mnt,
 {
        struct inode *inode = dentry->d_inode;
        generic_fillattr(inode, stat);
+       stat->dev = BTRFS_I(inode)->root->anon_super.s_dev;
        stat->blksize = PAGE_CACHE_SIZE;
        stat->blocks = (inode_get_bytes(inode) +
                        BTRFS_I(inode)->delalloc_bytes) >> 9;
@@ -4559,6 +4570,11 @@ static int btrfs_rename(struct inode * old_dir, struct dentry *old_dentry,
        u64 index = 0;
        int ret;
 
+       /* we're not allowed to rename between subvolumes */
+       if (BTRFS_I(old_inode)->root->root_key.objectid !=
+           BTRFS_I(new_dir)->root->root_key.objectid)
+               return -EXDEV;
+
        if (S_ISDIR(old_inode->i_mode) && new_inode &&
            new_inode->i_size > BTRFS_EMPTY_DIR_SIZE) {
                return -ENOTEMPTY;
@@ -4598,7 +4614,7 @@ static int btrfs_rename(struct inode * old_dir, struct dentry *old_dentry,
                }
 
        }
-       ret = btrfs_set_inode_index(new_dir, old_inode, &index);
+       ret = btrfs_set_inode_index(new_dir, &index);
        if (ret)
                goto out_fail;
 
@@ -4625,6 +4641,9 @@ int btrfs_start_delalloc_inodes(struct btrfs_root *root)
        struct inode *inode;
        unsigned long flags;
 
+       if (root->fs_info->sb->s_flags & MS_RDONLY)
+               return -EROFS;
+
        spin_lock_irqsave(&root->fs_info->delalloc_lock, flags);
        while(!list_empty(head)) {
                binode = list_entry(head->next, struct btrfs_inode,
@@ -4911,6 +4930,7 @@ static int btrfs_permission(struct inode *inode, int mask)
 }
 
 static struct inode_operations btrfs_dir_inode_operations = {
+       .getattr        = btrfs_getattr,
        .lookup         = btrfs_lookup,
        .create         = btrfs_create,
        .unlink         = btrfs_unlink,