static int btrfs_defrag_file(struct file *file, struct btrfs_ioctl_defrag_range_args *range) { struct inode *inode = fdentry(file)->d_inode; struct btrfs_root *root = BTRFS_I(inode)->root; struct extent_io_tree *io_tree = &BTRFS_I(inode)->io_tree; struct btrfs_ordered_extent *ordered; struct page *page; unsigned long last_index; unsigned long ra_pages = root->fs_info->bdi.ra_pages; unsigned long total_read = 0; u64 page_start; u64 page_end; u64 last_len = 0; u64 skip = 0; u64 defrag_end = 0; unsigned long i; int ret; if (inode->i_size == 0) return 0; if (range->start + range->len > range->start) { last_index = min_t(u64, inode->i_size - 1, range->start + range->len - 1) >> PAGE_CACHE_SHIFT; } else {
/* * @value: "" makes the attribute to empty, NULL removes it */ int __btrfs_setxattr(struct btrfs_trans_handle *trans, struct inode *inode, const char *name, const void *value, size_t size, int flags) { struct btrfs_root *root = BTRFS_I(inode)->root; int ret; if (trans) return do_setxattr(trans, inode, name, value, size, flags); trans = btrfs_start_transaction(root, 2); if (IS_ERR(trans)) return PTR_ERR(trans); ret = do_setxattr(trans, inode, name, value, size, flags); if (ret) goto out; inode_inc_iversion(inode); inode->i_ctime = current_fs_time(inode->i_sb); set_bit(BTRFS_INODE_COPY_EVERYTHING, &BTRFS_I(inode)->runtime_flags); ret = btrfs_update_inode(trans, root, inode); BUG_ON(ret); out: btrfs_end_transaction(trans, root); return ret; }
int btrfs_getxattr(struct inode *inode, const char *name, void *buffer, size_t size) { struct btrfs_dir_item *di; struct btrfs_root *root = BTRFS_I(inode)->root; struct btrfs_path *path; struct extent_buffer *leaf; int ret = 0; unsigned long data_ptr; path = btrfs_alloc_path(); if (!path) return -ENOMEM; /* lookup the xattr by name */ di = btrfs_lookup_xattr(NULL, root, path, btrfs_ino(BTRFS_I(inode)), name, strlen(name), 0); if (!di) { ret = -ENODATA; goto out; } else if (IS_ERR(di)) { ret = PTR_ERR(di); goto out; } leaf = path->nodes[0]; /* if size is 0, that means we want the size of the attr */ if (!size) { ret = btrfs_dir_data_len(leaf, di); goto out; } /* now get the data out of our dir_item */ if (btrfs_dir_data_len(leaf, di) > size) { ret = -ERANGE; goto out; } /* * The way things are packed into the leaf is like this * |struct btrfs_dir_item|name|data| * where name is the xattr name, so security.foo, and data is the * content of the xattr. data_ptr points to the location in memory * where the data starts in the in memory leaf */ data_ptr = (unsigned long)((char *)(di + 1) + btrfs_dir_name_len(leaf, di)); read_extent_buffer(leaf, buffer, data_ptr, btrfs_dir_data_len(leaf, di)); ret = btrfs_dir_data_len(leaf, di); out: btrfs_free_path(path); return ret; }
/* * Create a new subvolume below @parent. This is largely modeled after * sys_mkdirat and vfs_mkdir, but we only do a single component lookup * inside this filesystem so it's quite a bit simpler. */ static noinline int btrfs_mksubvol(struct path *parent, char *name, int namelen, struct btrfs_root *snap_src) { struct inode *dir = parent->dentry->d_inode; struct dentry *dentry; int error; mutex_lock_nested(&dir->i_mutex, I_MUTEX_PARENT); dentry = lookup_one_len(name, parent->dentry, namelen); error = PTR_ERR(dentry); if (IS_ERR(dentry)) goto out_unlock; error = -EEXIST; if (dentry->d_inode) goto out_dput; error = mnt_want_write(parent->mnt); if (error) goto out_dput; error = btrfs_may_create(dir, dentry); if (error) goto out_drop_write; down_read(&BTRFS_I(dir)->root->fs_info->subvol_sem); if (btrfs_root_refs(&BTRFS_I(dir)->root->root_item) == 0) goto out_up_read; if (snap_src) { error = create_snapshot(snap_src, dentry, name, namelen); } else { error = create_subvol(BTRFS_I(dir)->root, dentry, name, namelen); } if (!error) fsnotify_mkdir(dir, dentry); out_up_read: up_read(&BTRFS_I(dir)->root->fs_info->subvol_sem); out_drop_write: mnt_drop_write(parent->mnt); out_dput: dput(dentry); out_unlock: mutex_unlock(&dir->i_mutex); return error; }
static struct dentry *btrfs_get_parent(struct dentry *child) { struct inode *dir = d_inode(child); struct btrfs_fs_info *fs_info = btrfs_sb(dir->i_sb); struct btrfs_root *root = BTRFS_I(dir)->root; struct btrfs_path *path; struct extent_buffer *leaf; struct btrfs_root_ref *ref; struct btrfs_key key; struct btrfs_key found_key; int ret; path = btrfs_alloc_path(); if (!path) return ERR_PTR(-ENOMEM); if (btrfs_ino(BTRFS_I(dir)) == BTRFS_FIRST_FREE_OBJECTID) { key.objectid = root->root_key.objectid; key.type = BTRFS_ROOT_BACKREF_KEY; key.offset = (u64)-1; root = fs_info->tree_root; } else { key.objectid = btrfs_ino(BTRFS_I(dir)); key.type = BTRFS_INODE_REF_KEY; key.offset = (u64)-1; } ret = btrfs_search_slot(NULL, root, &key, path, 0, 0); if (ret < 0) goto fail; BUG_ON(ret == 0); /* Key with offset of -1 found */ if (path->slots[0] == 0) { ret = -ENOENT; goto fail; } path->slots[0]--; leaf = path->nodes[0]; btrfs_item_key_to_cpu(leaf, &found_key, path->slots[0]); if (found_key.objectid != key.objectid || found_key.type != key.type) { ret = -ENOENT; goto fail; } if (found_key.type == BTRFS_ROOT_BACKREF_KEY) { ref = btrfs_item_ptr(leaf, path->slots[0], struct btrfs_root_ref); key.objectid = btrfs_root_ref_dirid(leaf, ref); } else {
static int btrfs_encode_fh(struct dentry *dentry, u32 *fh, int *max_len, int connectable) { struct btrfs_fid *fid = (struct btrfs_fid *)fh; struct inode *inode = dentry->d_inode; int len = *max_len; int type; if (connectable && (len < BTRFS_FID_SIZE_CONNECTABLE)) { *max_len = BTRFS_FID_SIZE_CONNECTABLE; return 255; } else if (len < BTRFS_FID_SIZE_NON_CONNECTABLE) { *max_len = BTRFS_FID_SIZE_NON_CONNECTABLE; return 255; } len = BTRFS_FID_SIZE_NON_CONNECTABLE; type = FILEID_BTRFS_WITHOUT_PARENT; fid->objectid = btrfs_ino(inode); fid->root_objectid = BTRFS_I(inode)->root->objectid; fid->gen = inode->i_generation; if (connectable && !S_ISDIR(inode->i_mode)) { struct inode *parent; u64 parent_root_id; spin_lock(&dentry->d_lock); parent = dentry->d_parent->d_inode; fid->parent_objectid = BTRFS_I(parent)->location.objectid; fid->parent_gen = parent->i_generation; parent_root_id = BTRFS_I(parent)->root->objectid; spin_unlock(&dentry->d_lock); if (parent_root_id != fid->root_objectid) { fid->parent_root_objectid = parent_root_id; len = BTRFS_FID_SIZE_CONNECTABLE_ROOT; type = FILEID_BTRFS_WITH_PARENT_ROOT; } else { len = BTRFS_FID_SIZE_CONNECTABLE; type = FILEID_BTRFS_WITH_PARENT; } } *max_len = len; return type; }
int __btrfs_setxattr(struct btrfs_trans_handle *trans, struct inode *inode, const char *name, const void *value, size_t size, int flags) { struct btrfs_root *root = BTRFS_I(inode)->root; int ret; if (trans) return do_setxattr(trans, inode, name, value, size, flags); ret = btrfs_reserve_metadata_space(root, 2); if (ret) return ret; trans = btrfs_start_transaction(root, 1); if (!trans) { ret = -ENOMEM; goto out; } btrfs_set_trans_block_group(trans, inode); ret = do_setxattr(trans, inode, name, value, size, flags); if (ret) goto out; inode->i_ctime = CURRENT_TIME; ret = btrfs_update_inode(trans, root, inode); BUG_ON(ret); out: btrfs_end_transaction_throttle(trans, root); btrfs_unreserve_metadata_space(root, 2); return ret; }
int btrfs_removexattr(struct dentry *dentry, const char *name) { struct btrfs_root *root = BTRFS_I(dentry->d_inode)->root; /* * The permission on security.* and system.* is not checked * in permission(). */ if (btrfs_root_readonly(root)) return -EROFS; /* * If this is a request for a synthetic attribute in the system.* * namespace use the generic infrastructure to resolve a handler * for it via sb->s_xattr. */ if (!strncmp(name, XATTR_SYSTEM_PREFIX, XATTR_SYSTEM_PREFIX_LEN)) return generic_removexattr(dentry, name); if (!btrfs_is_valid_xattr(name)) return -EOPNOTSUPP; return __btrfs_setxattr(NULL, dentry->d_inode, name, NULL, 0, XATTR_REPLACE); }
int btrfs_setxattr(struct dentry *dentry, const char *name, const void *value, size_t size, int flags) { struct btrfs_root *root = BTRFS_I(dentry->d_inode)->root; /* * The permission on security.* and system.* is not checked * in permission(). */ if (btrfs_root_readonly(root)) return -EROFS; /* * If this is a request for a synthetic attribute in the system.* * namespace use the generic infrastructure to resolve a handler * for it via sb->s_xattr. */ if (!strncmp(name, XATTR_SYSTEM_PREFIX, XATTR_SYSTEM_PREFIX_LEN)) return generic_setxattr(dentry, name, value, size, flags); if (!btrfs_is_valid_xattr(name)) return -EOPNOTSUPP; if (!strncmp(name, XATTR_BTRFS_PREFIX, XATTR_BTRFS_PREFIX_LEN)) return btrfs_set_prop(dentry->d_inode, name, value, size, flags); if (size == 0) value = ""; /* empty EA, do not remove */ return __btrfs_setxattr(NULL, dentry->d_inode, name, value, size, flags); }
static int btrfs_statfs(struct dentry *dentry, struct kstatfs *buf) { struct btrfs_root *root = btrfs_sb(dentry->d_sb); struct btrfs_super_block *disk_super = &root->fs_info->super_copy; int bits = dentry->d_sb->s_blocksize_bits; __be32 *fsid = (__be32 *)root->fs_info->fsid; buf->f_namelen = BTRFS_NAME_LEN; buf->f_blocks = btrfs_super_total_bytes(disk_super) >> bits; buf->f_bfree = buf->f_blocks - (btrfs_super_bytes_used(disk_super) >> bits); buf->f_bavail = buf->f_bfree; buf->f_bsize = dentry->d_sb->s_blocksize; buf->f_type = BTRFS_SUPER_MAGIC; /* We treat it as constant endianness (it doesn't matter _which_) because we want the fsid to come out the same whether mounted on a big-endian or little-endian host */ buf->f_fsid.val[0] = be32_to_cpu(fsid[0]) ^ be32_to_cpu(fsid[2]); buf->f_fsid.val[1] = be32_to_cpu(fsid[1]) ^ be32_to_cpu(fsid[3]); /* Mask in the root object ID too, to disambiguate subvols */ buf->f_fsid.val[0] ^= BTRFS_I(dentry->d_inode)->root->objectid >> 32; buf->f_fsid.val[1] ^= BTRFS_I(dentry->d_inode)->root->objectid; return 0; }
int btrfs_removexattr(struct dentry *dentry, const char *name) { struct btrfs_root *root = BTRFS_I(dentry->d_inode)->root; /* */ if (btrfs_root_readonly(root)) return -EROFS; /* */ if (!strncmp(name, XATTR_SYSTEM_PREFIX, XATTR_SYSTEM_PREFIX_LEN)) return generic_removexattr(dentry, name); if (!btrfs_is_valid_xattr(name)) return -EOPNOTSUPP; return __btrfs_setxattr(NULL, dentry->d_inode, name, NULL, 0, XATTR_REPLACE); }
int btrfs_setxattr(struct dentry *dentry, const char *name, const void *value, size_t size, int flags) { struct btrfs_root *root = BTRFS_I(dentry->d_inode)->root; /* */ if (btrfs_root_readonly(root)) return -EROFS; /* */ if (!strncmp(name, XATTR_SYSTEM_PREFIX, XATTR_SYSTEM_PREFIX_LEN)) return generic_setxattr(dentry, name, value, size, flags); if (!btrfs_is_valid_xattr(name)) return -EOPNOTSUPP; if (size == 0) value = ""; /* */ return __btrfs_setxattr(NULL, dentry->d_inode, name, value, size, flags); }
/* * @value: "" makes the attribute to empty, NULL removes it */ int __btrfs_setxattr(struct btrfs_trans_handle *trans, struct inode *inode, const char *name, const void *value, size_t size, int flags) { struct btrfs_root *root = BTRFS_I(inode)->root; int ret; if (trans) return do_setxattr(trans, inode, name, value, size, flags); trans = btrfs_start_transaction(root, 2); if (IS_ERR(trans)) return PTR_ERR(trans); ret = do_setxattr(trans, inode, name, value, size, flags); if (ret) goto out; inode->i_ctime = CURRENT_TIME; ret = btrfs_update_inode(trans, root, inode); BUG_ON(ret); out: btrfs_end_transaction_throttle(trans, root); return ret; }
/* * after copy_from_user, pages need to be dirtied and we need to make * sure holes are created between the current EOF and the start of * any next extents (if required). * * this also makes the decision about creating an inline extent vs * doing real data extents, marking pages dirty and delalloc as required. */ static noinline int dirty_and_release_pages(struct btrfs_trans_handle *trans, struct btrfs_root *root, struct file *file, struct page **pages, size_t num_pages, loff_t pos, size_t write_bytes) { int err = 0; int i; struct inode *inode = fdentry(file)->d_inode; struct extent_io_tree *io_tree = &BTRFS_I(inode)->io_tree; u64 hint_byte; u64 num_bytes; u64 start_pos; u64 end_of_last_block; u64 end_pos = pos + write_bytes; loff_t isize = i_size_read(inode); start_pos = pos & ~((u64)root->sectorsize - 1); num_bytes = (write_bytes + pos - start_pos + root->sectorsize - 1) & ~((u64)root->sectorsize - 1); end_of_last_block = start_pos + num_bytes - 1; lock_extent(io_tree, start_pos, end_of_last_block, GFP_NOFS); trans = btrfs_join_transaction(root, 1); if (!trans) { err = -ENOMEM; goto out_unlock; } btrfs_set_trans_block_group(trans, inode); hint_byte = 0; set_extent_uptodate(io_tree, start_pos, end_of_last_block, GFP_NOFS); /* check for reserved extents on each page, we don't want * to reset the delalloc bit on things that already have * extents reserved. */ btrfs_set_extent_delalloc(inode, start_pos, end_of_last_block); for (i = 0; i < num_pages; i++) { struct page *p = pages[i]; SetPageUptodate(p); ClearPageChecked(p); set_page_dirty(p); } if (end_pos > isize) { i_size_write(inode, end_pos); /* we've only changed i_size in ram, and we haven't updated * the disk i_size. There is no need to log the inode * at this time. */ } err = btrfs_end_transaction(trans, root); out_unlock: unlock_extent(io_tree, start_pos, end_of_last_block, GFP_NOFS); return err; }
int btrfs_removexattr(struct dentry *dentry, const char *name) { struct btrfs_root *root = BTRFS_I(d_inode(dentry))->root; if (btrfs_root_readonly(root)) return -EROFS; return generic_removexattr(dentry, name); }
/* * Inherit flags from the parent inode. * * Unlike extN we don't have any flags we don't want to inherit currently. */ void btrfs_inherit_iflags(struct inode *inode, struct inode *dir) { unsigned int flags; if (!dir) return; flags = BTRFS_I(dir)->flags; if (S_ISREG(inode->i_mode)) flags &= ~BTRFS_INODE_DIRSYNC; else if (!S_ISDIR(inode->i_mode)) flags &= (BTRFS_INODE_NODUMP | BTRFS_INODE_NOATIME); BTRFS_I(inode)->flags = flags; btrfs_update_iflags(inode); }
static int do_setxattr(struct btrfs_trans_handle *trans, struct inode *inode, const char *name, const void *value, size_t size, int flags) { struct btrfs_dir_item *di; struct btrfs_root *root = BTRFS_I(inode)->root; struct btrfs_path *path; size_t name_len = strlen(name); int ret = 0; if (name_len + size > BTRFS_MAX_XATTR_SIZE(root)) return -ENOSPC; path = btrfs_alloc_path(); if (!path) return -ENOMEM; /* first lets see if we already have this xattr */ di = btrfs_lookup_xattr(trans, root, path, btrfs_ino(inode), name, strlen(name), -1); if (IS_ERR(di)) { ret = PTR_ERR(di); goto out; } /* ok we already have this xattr, lets remove it */ if (di) { /* if we want create only exit */ if (flags & XATTR_CREATE) { ret = -EEXIST; goto out; } ret = btrfs_delete_one_dir_name(trans, root, path, di); BUG_ON(ret); btrfs_release_path(path); /* if we don't have a value then we are removing the xattr */ if (!value) goto out; } else { btrfs_release_path(path); if (flags & XATTR_REPLACE) { /* we couldn't find the attr to replace */ ret = -ENODATA; goto out; } } /* ok we have to create a completely new xattr */ ret = btrfs_insert_xattr_item(trans, root, path, btrfs_ino(inode), name, name_len, value, size); BUG_ON(ret); out: btrfs_free_path(path); return ret; }
static struct dentry *btrfs_get_parent(struct dentry *child) { struct inode *dir = child->d_inode; struct btrfs_root *root = BTRFS_I(dir)->root; struct btrfs_key key; struct btrfs_path *path; struct extent_buffer *leaf; int slot; u64 objectid; int ret; path = btrfs_alloc_path(); key.objectid = dir->i_ino; btrfs_set_key_type(&key, BTRFS_INODE_REF_KEY); key.offset = (u64)-1; ret = btrfs_search_slot(NULL, root, &key, path, 0, 0); if (ret < 0) { /* Error */ btrfs_free_path(path); return ERR_PTR(ret); } leaf = path->nodes[0]; slot = path->slots[0]; if (ret) { /* btrfs_search_slot() returns the slot where we'd want to insert a backref for parent inode #0xFFFFFFFFFFFFFFFF. The _real_ backref, telling us what the parent inode _actually_ is, will be in the slot _before_ the one that btrfs_search_slot() returns. */ if (!slot) { /* Unless there is _no_ key in the tree before... */ btrfs_free_path(path); return ERR_PTR(-EIO); } slot--; } btrfs_item_key_to_cpu(leaf, &key, slot); btrfs_free_path(path); if (key.objectid != dir->i_ino || key.type != BTRFS_INODE_REF_KEY) return ERR_PTR(-EINVAL); objectid = key.offset; /* If we are already at the root of a subvol, return the real root */ if (objectid == dir->i_ino) return dget(dir->i_sb->s_root); /* Build a new key for the inode item */ key.objectid = objectid; btrfs_set_key_type(&key, BTRFS_INODE_ITEM_KEY); key.offset = 0; return d_obtain_alias(btrfs_iget(root->fs_info->sb, &key, root, NULL)); }
static int btrfs_ioctl_getflags(struct file *file, void __user *arg) { struct btrfs_inode *ip = BTRFS_I(file->f_path.dentry->d_inode); unsigned int flags = btrfs_flags_to_ioctl(ip->flags); if (copy_to_user(arg, &flags, sizeof(flags))) return -EFAULT; return 0; }
int btrfs_setxattr(struct dentry *dentry, const char *name, const void *value, size_t size, int flags) { struct btrfs_root *root = BTRFS_I(d_inode(dentry))->root; if (btrfs_root_readonly(root)) return -EROFS; return generic_setxattr(dentry, name, value, size, flags); }
ssize_t __btrfs_getxattr(struct inode *inode, const char *name, void *buffer, size_t size) { struct btrfs_dir_item *di; struct btrfs_root *root = BTRFS_I(inode)->root; struct btrfs_path *path; struct extent_buffer *leaf; int ret = 0; unsigned long data_ptr; path = btrfs_alloc_path(); if (!path) return -ENOMEM; /* */ di = btrfs_lookup_xattr(NULL, root, path, btrfs_ino(inode), name, strlen(name), 0); if (!di) { ret = -ENODATA; goto out; } else if (IS_ERR(di)) { ret = PTR_ERR(di); goto out; } leaf = path->nodes[0]; /* */ if (!size) { ret = btrfs_dir_data_len(leaf, di); goto out; } /* */ if (btrfs_dir_data_len(leaf, di) > size) { ret = -ERANGE; goto out; } /* */ data_ptr = (unsigned long)((char *)(di + 1) + btrfs_dir_name_len(leaf, di)); read_extent_buffer(leaf, buffer, data_ptr, btrfs_dir_data_len(leaf, di)); ret = btrfs_dir_data_len(leaf, di); out: btrfs_free_path(path); return ret; }
static int btrfs_encode_fh(struct inode *inode, u32 *fh, int *max_len, struct inode *parent) { struct btrfs_fid *fid = (struct btrfs_fid *)fh; int len = *max_len; int type; if (parent && (len < BTRFS_FID_SIZE_CONNECTABLE)) { *max_len = BTRFS_FID_SIZE_CONNECTABLE; return FILEID_INVALID; } else if (len < BTRFS_FID_SIZE_NON_CONNECTABLE) { *max_len = BTRFS_FID_SIZE_NON_CONNECTABLE; return FILEID_INVALID; } len = BTRFS_FID_SIZE_NON_CONNECTABLE; type = FILEID_BTRFS_WITHOUT_PARENT; fid->objectid = btrfs_ino(BTRFS_I(inode)); fid->root_objectid = BTRFS_I(inode)->root->objectid; fid->gen = inode->i_generation; if (parent) { u64 parent_root_id; fid->parent_objectid = BTRFS_I(parent)->location.objectid; fid->parent_gen = parent->i_generation; parent_root_id = BTRFS_I(parent)->root->objectid; if (parent_root_id != fid->root_objectid) { fid->parent_root_objectid = parent_root_id; len = BTRFS_FID_SIZE_CONNECTABLE_ROOT; type = FILEID_BTRFS_WITH_PARENT_ROOT; } else { len = BTRFS_FID_SIZE_CONNECTABLE; type = FILEID_BTRFS_WITH_PARENT; } } *max_len = len; return type; }
/* pop a record for an inode into the defrag tree. The lock * must be held already * * If you're inserting a record for an older transid than an * existing record, the transid already in the tree is lowered * * If an existing record is found the defrag item you * pass in is freed */ static void __btrfs_add_inode_defrag(struct inode *inode, struct inode_defrag *defrag) { struct btrfs_root *root = BTRFS_I(inode)->root; struct inode_defrag *entry; struct rb_node **p; struct rb_node *parent = NULL; int ret; p = &root->fs_info->defrag_inodes.rb_node; while (*p) { parent = *p; entry = rb_entry(parent, struct inode_defrag, rb_node); ret = __compare_inode_defrag(defrag, entry); if (ret < 0) p = &parent->rb_left; else if (ret > 0) p = &parent->rb_right; else { /* if we're reinserting an entry for * an old defrag run, make sure to * lower the transid of our existing record */ if (defrag->transid < entry->transid) entry->transid = defrag->transid; if (defrag->last_offset > entry->last_offset) entry->last_offset = defrag->last_offset; goto exists; } } set_bit(BTRFS_INODE_IN_DEFRAG, &BTRFS_I(inode)->runtime_flags); rb_link_node(&defrag->rb_node, parent, p); rb_insert_color(&defrag->rb_node, &root->fs_info->defrag_inodes); return; exists: kfree(defrag); return; }
/* * insert a defrag record for this inode if auto defrag is * enabled */ int btrfs_add_inode_defrag(struct btrfs_trans_handle *trans, struct inode *inode) { struct btrfs_root *root = BTRFS_I(inode)->root; struct inode_defrag *defrag; u64 transid; if (!btrfs_test_opt(root, AUTO_DEFRAG)) return 0; if (btrfs_fs_closing(root->fs_info)) return 0; if (test_bit(BTRFS_INODE_IN_DEFRAG, &BTRFS_I(inode)->runtime_flags)) return 0; if (trans) transid = trans->transid; else transid = BTRFS_I(inode)->root->last_trans; defrag = kzalloc(sizeof(*defrag), GFP_NOFS); if (!defrag) return -ENOMEM; defrag->ino = btrfs_ino(inode); defrag->transid = transid; defrag->root = root->root_key.objectid; spin_lock(&root->fs_info->defrag_inodes_lock); if (!test_bit(BTRFS_INODE_IN_DEFRAG, &BTRFS_I(inode)->runtime_flags)) __btrfs_add_inode_defrag(inode, defrag); else kfree(defrag); spin_unlock(&root->fs_info->defrag_inodes_lock); return 0; }
static noinline int finish_pending_snapshot(struct btrfs_fs_info *fs_info, struct btrfs_pending_snapshot *pending) { int ret; int namelen; u64 index = 0; struct btrfs_trans_handle *trans; struct inode *parent_inode; struct inode *inode; struct btrfs_root *parent_root; parent_inode = pending->dentry->d_parent->d_inode; parent_root = BTRFS_I(parent_inode)->root; trans = btrfs_join_transaction(parent_root, 1); /* * insert the directory item */ namelen = strlen(pending->name); ret = btrfs_set_inode_index(parent_inode, &index); ret = btrfs_insert_dir_item(trans, parent_root, pending->name, namelen, parent_inode->i_ino, &pending->root_key, BTRFS_FT_DIR, index); if (ret) goto fail; btrfs_i_size_write(parent_inode, parent_inode->i_size + namelen * 2); ret = btrfs_update_inode(trans, parent_root, parent_inode); BUG_ON(ret); ret = btrfs_add_root_ref(trans, parent_root->fs_info->tree_root, pending->root_key.objectid, parent_root->root_key.objectid, parent_inode->i_ino, index, pending->name, namelen); BUG_ON(ret); inode = btrfs_lookup_dentry(parent_inode, pending->dentry); d_instantiate(pending->dentry, inode); fail: btrfs_end_transaction(trans, fs_info->fs_root); return ret; }
/* * Update inode->i_flags based on the btrfs internal flags. */ void btrfs_update_iflags(struct inode *inode) { struct btrfs_inode *ip = BTRFS_I(inode); inode->i_flags &= ~(S_SYNC|S_APPEND|S_IMMUTABLE|S_NOATIME|S_DIRSYNC); if (ip->flags & BTRFS_INODE_SYNC) inode->i_flags |= S_SYNC; if (ip->flags & BTRFS_INODE_IMMUTABLE) inode->i_flags |= S_IMMUTABLE; if (ip->flags & BTRFS_INODE_APPEND) inode->i_flags |= S_APPEND; if (ip->flags & BTRFS_INODE_NOATIME) inode->i_flags |= S_NOATIME; if (ip->flags & BTRFS_INODE_DIRSYNC) inode->i_flags |= S_DIRSYNC; }
int btrfs_dedup_search(struct inode *inode, u64 file_pos, struct btrfs_dedup_hash *hash) { struct btrfs_fs_info *fs_info = BTRFS_I(inode)->root->fs_info; struct btrfs_dedup_info *dedup_info = fs_info->dedup_info; int ret = 0; if (WARN_ON(!dedup_info || !hash)) return 0; if (dedup_info->backend < BTRFS_DEDUP_BACKEND_LAST) { ret = generic_search(inode, file_pos, hash); if (ret == 0) { hash->num_bytes = 0; hash->bytenr = 0; } return ret; } return -EINVAL; }
static int generic_search(struct inode *inode, u64 file_pos, struct btrfs_dedup_hash *hash) { int ret; struct btrfs_root *root = BTRFS_I(inode)->root; struct btrfs_fs_info *fs_info = root->fs_info; struct btrfs_trans_handle *trans; struct btrfs_delayed_ref_root *delayed_refs; struct btrfs_delayed_ref_head *head; struct btrfs_dedup_info *dedup_info = fs_info->dedup_info; u64 bytenr; u64 tmp_bytenr; u32 num_bytes; trans = btrfs_join_transaction(root); if (IS_ERR(trans)) return PTR_ERR(trans); again: mutex_lock(&dedup_info->lock); ret = generic_search_hash(dedup_info, hash->hash, &bytenr, &num_bytes); if (ret <= 0) goto out; delayed_refs = &trans->transaction->delayed_refs; spin_lock(&delayed_refs->lock); head = btrfs_find_delayed_ref_head(trans, bytenr); if (!head) { /* * We can safely insert a new delayed_ref as long as we * hold delayed_refs->lock. * Only need to use atomic inc_extent_ref() */ ret = btrfs_inc_extent_ref_atomic(trans, root, bytenr, num_bytes, 0, root->root_key.objectid, btrfs_ino(inode), file_pos); spin_unlock(&delayed_refs->lock); if (ret == 0) { hash->bytenr = bytenr; hash->num_bytes = num_bytes; ret = 1; } goto out; } /* * We can't lock ref head with dedup_info->lock hold or we will cause * ABBA dead lock. */ mutex_unlock(&dedup_info->lock); ret = btrfs_delayed_ref_lock(trans, head); spin_unlock(&delayed_refs->lock); if (ret == -EAGAIN) goto again; mutex_lock(&dedup_info->lock); /* * Search again to ensure the hash is still here and bytenr didn't * change */ ret = generic_search_hash(dedup_info, hash->hash, &tmp_bytenr, &num_bytes); if (ret <= 0) { mutex_unlock(&head->mutex); goto out; } if (tmp_bytenr != bytenr) { mutex_unlock(&head->mutex); mutex_unlock(&dedup_info->lock); goto again; } hash->bytenr = bytenr; hash->num_bytes = num_bytes; /* * Increase the extent ref right now, to avoid delayed ref run * Or we may increase ref on non-exist extent. */ btrfs_inc_extent_ref(trans, root, bytenr, num_bytes, 0, root->root_key.objectid, btrfs_ino(inode), file_pos); mutex_unlock(&head->mutex); out: mutex_unlock(&dedup_info->lock); btrfs_end_transaction(trans, root); return ret; }
static int do_setxattr(struct btrfs_trans_handle *trans, struct inode *inode, const char *name, const void *value, size_t size, int flags) { struct btrfs_dir_item *di; struct btrfs_root *root = BTRFS_I(inode)->root; struct btrfs_path *path; size_t name_len = strlen(name); int ret = 0; if (name_len + size > BTRFS_MAX_XATTR_SIZE(root)) return -ENOSPC; path = btrfs_alloc_path(); if (!path) return -ENOMEM; if (flags & XATTR_REPLACE) { di = btrfs_lookup_xattr(trans, root, path, btrfs_ino(inode), name, name_len, -1); if (IS_ERR(di)) { ret = PTR_ERR(di); goto out; } else if (!di) { ret = -ENODATA; goto out; } ret = btrfs_delete_one_dir_name(trans, root, path, di); if (ret) goto out; btrfs_release_path(path); /* * remove the attribute */ if (!value) goto out; } again: ret = btrfs_insert_xattr_item(trans, root, path, btrfs_ino(inode), name, name_len, value, size); if (ret == -EEXIST) { if (flags & XATTR_CREATE) goto out; /* * We can't use the path we already have since we won't have the * proper locking for a delete, so release the path and * re-lookup to delete the thing. */ btrfs_release_path(path); di = btrfs_lookup_xattr(trans, root, path, btrfs_ino(inode), name, name_len, -1); if (IS_ERR(di)) { ret = PTR_ERR(di); goto out; } else if (!di) { /* Shouldn't happen but just in case... */ btrfs_release_path(path); goto again; } ret = btrfs_delete_one_dir_name(trans, root, path, di); if (ret) goto out; /* * We have a value to set, so go back and try to insert it now. */ if (value) { btrfs_release_path(path); goto again; } } out: btrfs_free_path(path); return ret; }
ssize_t btrfs_listxattr(struct dentry *dentry, char *buffer, size_t size) { struct btrfs_key key, found_key; struct inode *inode = dentry->d_inode; struct btrfs_root *root = BTRFS_I(inode)->root; struct btrfs_path *path; struct extent_buffer *leaf; struct btrfs_dir_item *di; int ret = 0, slot; size_t total_size = 0, size_left = size; unsigned long name_ptr; size_t name_len; /* * ok we want all objects associated with this id. * NOTE: we set key.offset = 0; because we want to start with the * first xattr that we find and walk forward */ key.objectid = btrfs_ino(inode); btrfs_set_key_type(&key, BTRFS_XATTR_ITEM_KEY); key.offset = 0; path = btrfs_alloc_path(); if (!path) return -ENOMEM; path->reada = 2; /* search for our xattrs */ ret = btrfs_search_slot(NULL, root, &key, path, 0, 0); if (ret < 0) goto err; while (1) { leaf = path->nodes[0]; slot = path->slots[0]; /* this is where we start walking through the path */ if (slot >= btrfs_header_nritems(leaf)) { /* * if we've reached the last slot in this leaf we need * to go to the next leaf and reset everything */ ret = btrfs_next_leaf(root, path); if (ret < 0) goto err; else if (ret > 0) break; continue; } btrfs_item_key_to_cpu(leaf, &found_key, slot); /* check to make sure this item is what we want */ if (found_key.objectid != key.objectid) break; if (btrfs_key_type(&found_key) != BTRFS_XATTR_ITEM_KEY) break; di = btrfs_item_ptr(leaf, slot, struct btrfs_dir_item); if (verify_dir_item(root, leaf, di)) continue; name_len = btrfs_dir_name_len(leaf, di); total_size += name_len + 1; /* we are just looking for how big our buffer needs to be */ if (!size) goto next; if (!buffer || (name_len + 1) > size_left) { ret = -ERANGE; goto err; } name_ptr = (unsigned long)(di + 1); read_extent_buffer(leaf, buffer, name_ptr, name_len); buffer[name_len] = '\0'; size_left -= name_len + 1; buffer += name_len + 1; next: path->slots[0]++; } ret = total_size; err: btrfs_free_path(path); return ret; }