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);
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;
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;
}
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);
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);
}
return 0;
filp->f_pos = 2;
}
-
path = btrfs_alloc_path();
path->reada = 2;
path->slots[0]++;
}
}
+
advance = 1;
item = btrfs_item_nr(leaf, slot);
btrfs_item_key_to_cpu(leaf, &found_key, slot);
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;
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) {
* 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;
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);
}
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;
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) {
* 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;
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);
if (error)
return error;
- atomic_inc(&inode->i_count);
d_instantiate(dentry, inode);
return 0;
}
{
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;
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;
}
}
- ret = btrfs_set_inode_index(new_dir, old_inode, &index);
+ ret = btrfs_set_inode_index(new_dir, &index);
if (ret)
goto out_fail;
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,
}
static struct inode_operations btrfs_dir_inode_operations = {
+ .getattr = btrfs_getattr,
.lookup = btrfs_lookup,
.create = btrfs_create,
.unlink = btrfs_unlink,