Merge git://git.kernel.org/pub/scm/linux/kernel/git/mason/btrfs-unstable
* git://git.kernel.org/pub/scm/linux/kernel/git/mason/btrfs-unstable: (24 commits) Btrfs: don't use migrate page without CONFIG_MIGRATION Btrfs: deal with DIO bios that span more than one ordered extent Btrfs: setup blank root and fs_info for mount time Btrfs: fix fiemap Btrfs - fix race between btrfs_get_sb() and umount Btrfs: update inode ctime when using links Btrfs: make sure new inode size is ok in fallocate Btrfs: fix typo in fallocate to make it honor actual size Btrfs: avoid NULL pointer deref in try_release_extent_buffer Btrfs: make btrfs_add_nondir take parent inode as an argument Btrfs: hold i_mutex when calling btrfs_log_dentry_safe Btrfs: use dget_parent where we can UPDATED Btrfs: fix more ESTALE problems with NFS Btrfs: handle NFS lookups properly btrfs: make 1-bit signed fileds unsigned btrfs: Show device attr correctly for symlinks btrfs: Set file size correctly in file clone btrfs: Check if dest_offset is block-size aligned before cloning file Btrfs: handle the space_cache option properly btrfs: Fix early enospc because 'unused' calculated with wrong sign. ...
This commit is contained in:
Коммит
aa3fc52546
|
@ -91,23 +91,10 @@ static inline int compressed_bio_size(struct btrfs_root *root,
|
|||
static struct bio *compressed_bio_alloc(struct block_device *bdev,
|
||||
u64 first_byte, gfp_t gfp_flags)
|
||||
{
|
||||
struct bio *bio;
|
||||
int nr_vecs;
|
||||
|
||||
nr_vecs = bio_get_nr_vecs(bdev);
|
||||
bio = bio_alloc(gfp_flags, nr_vecs);
|
||||
|
||||
if (bio == NULL && (current->flags & PF_MEMALLOC)) {
|
||||
while (!bio && (nr_vecs /= 2))
|
||||
bio = bio_alloc(gfp_flags, nr_vecs);
|
||||
}
|
||||
|
||||
if (bio) {
|
||||
bio->bi_size = 0;
|
||||
bio->bi_bdev = bdev;
|
||||
bio->bi_sector = first_byte >> 9;
|
||||
}
|
||||
return bio;
|
||||
return btrfs_bio_alloc(bdev, first_byte >> 9, nr_vecs, gfp_flags);
|
||||
}
|
||||
|
||||
static int check_compressed_csum(struct inode *inode,
|
||||
|
|
|
@ -808,9 +808,9 @@ struct btrfs_block_group_cache {
|
|||
int extents_thresh;
|
||||
int free_extents;
|
||||
int total_bitmaps;
|
||||
int ro:1;
|
||||
int dirty:1;
|
||||
int iref:1;
|
||||
unsigned int ro:1;
|
||||
unsigned int dirty:1;
|
||||
unsigned int iref:1;
|
||||
|
||||
int disk_cache_state;
|
||||
|
||||
|
|
|
@ -28,6 +28,7 @@
|
|||
#include <linux/freezer.h>
|
||||
#include <linux/crc32c.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/migrate.h>
|
||||
#include "compat.h"
|
||||
#include "ctree.h"
|
||||
#include "disk-io.h"
|
||||
|
@ -355,6 +356,8 @@ static int csum_dirty_buffer(struct btrfs_root *root, struct page *page)
|
|||
ret = btree_read_extent_buffer_pages(root, eb, start + PAGE_CACHE_SIZE,
|
||||
btrfs_header_generation(eb));
|
||||
BUG_ON(ret);
|
||||
WARN_ON(!btrfs_header_flag(eb, BTRFS_HEADER_FLAG_WRITTEN));
|
||||
|
||||
found_start = btrfs_header_bytenr(eb);
|
||||
if (found_start != start) {
|
||||
WARN_ON(1);
|
||||
|
@ -693,6 +696,29 @@ static int btree_submit_bio_hook(struct inode *inode, int rw, struct bio *bio,
|
|||
__btree_submit_bio_done);
|
||||
}
|
||||
|
||||
static int btree_migratepage(struct address_space *mapping,
|
||||
struct page *newpage, struct page *page)
|
||||
{
|
||||
/*
|
||||
* we can't safely write a btree page from here,
|
||||
* we haven't done the locking hook
|
||||
*/
|
||||
if (PageDirty(page))
|
||||
return -EAGAIN;
|
||||
/*
|
||||
* Buffers may be managed in a filesystem specific way.
|
||||
* We must have no buffers or drop them.
|
||||
*/
|
||||
if (page_has_private(page) &&
|
||||
!try_to_release_page(page, GFP_KERNEL))
|
||||
return -EAGAIN;
|
||||
#ifdef CONFIG_MIGRATION
|
||||
return migrate_page(mapping, newpage, page);
|
||||
#else
|
||||
return -ENOSYS;
|
||||
#endif
|
||||
}
|
||||
|
||||
static int btree_writepage(struct page *page, struct writeback_control *wbc)
|
||||
{
|
||||
struct extent_io_tree *tree;
|
||||
|
@ -707,8 +733,7 @@ static int btree_writepage(struct page *page, struct writeback_control *wbc)
|
|||
}
|
||||
|
||||
redirty_page_for_writepage(wbc, page);
|
||||
eb = btrfs_find_tree_block(root, page_offset(page),
|
||||
PAGE_CACHE_SIZE);
|
||||
eb = btrfs_find_tree_block(root, page_offset(page), PAGE_CACHE_SIZE);
|
||||
WARN_ON(!eb);
|
||||
|
||||
was_dirty = test_and_set_bit(EXTENT_BUFFER_DIRTY, &eb->bflags);
|
||||
|
@ -799,6 +824,9 @@ static const struct address_space_operations btree_aops = {
|
|||
.releasepage = btree_releasepage,
|
||||
.invalidatepage = btree_invalidatepage,
|
||||
.sync_page = block_sync_page,
|
||||
#ifdef CONFIG_MIGRATION
|
||||
.migratepage = btree_migratepage,
|
||||
#endif
|
||||
};
|
||||
|
||||
int readahead_tree_block(struct btrfs_root *root, u64 bytenr, u32 blocksize,
|
||||
|
@ -1538,10 +1566,8 @@ struct btrfs_root *open_ctree(struct super_block *sb,
|
|||
GFP_NOFS);
|
||||
struct btrfs_root *csum_root = kzalloc(sizeof(struct btrfs_root),
|
||||
GFP_NOFS);
|
||||
struct btrfs_root *tree_root = kzalloc(sizeof(struct btrfs_root),
|
||||
GFP_NOFS);
|
||||
struct btrfs_fs_info *fs_info = kzalloc(sizeof(*fs_info),
|
||||
GFP_NOFS);
|
||||
struct btrfs_root *tree_root = btrfs_sb(sb);
|
||||
struct btrfs_fs_info *fs_info = tree_root->fs_info;
|
||||
struct btrfs_root *chunk_root = kzalloc(sizeof(struct btrfs_root),
|
||||
GFP_NOFS);
|
||||
struct btrfs_root *dev_root = kzalloc(sizeof(struct btrfs_root),
|
||||
|
|
|
@ -232,9 +232,85 @@ fail:
|
|||
return ERR_PTR(ret);
|
||||
}
|
||||
|
||||
static int btrfs_get_name(struct dentry *parent, char *name,
|
||||
struct dentry *child)
|
||||
{
|
||||
struct inode *inode = child->d_inode;
|
||||
struct inode *dir = parent->d_inode;
|
||||
struct btrfs_path *path;
|
||||
struct btrfs_root *root = BTRFS_I(dir)->root;
|
||||
struct btrfs_inode_ref *iref;
|
||||
struct btrfs_root_ref *rref;
|
||||
struct extent_buffer *leaf;
|
||||
unsigned long name_ptr;
|
||||
struct btrfs_key key;
|
||||
int name_len;
|
||||
int ret;
|
||||
|
||||
if (!dir || !inode)
|
||||
return -EINVAL;
|
||||
|
||||
if (!S_ISDIR(dir->i_mode))
|
||||
return -EINVAL;
|
||||
|
||||
path = btrfs_alloc_path();
|
||||
if (!path)
|
||||
return -ENOMEM;
|
||||
path->leave_spinning = 1;
|
||||
|
||||
if (inode->i_ino == BTRFS_FIRST_FREE_OBJECTID) {
|
||||
key.objectid = BTRFS_I(inode)->root->root_key.objectid;
|
||||
key.type = BTRFS_ROOT_BACKREF_KEY;
|
||||
key.offset = (u64)-1;
|
||||
root = root->fs_info->tree_root;
|
||||
} else {
|
||||
key.objectid = inode->i_ino;
|
||||
key.offset = dir->i_ino;
|
||||
key.type = BTRFS_INODE_REF_KEY;
|
||||
}
|
||||
|
||||
ret = btrfs_search_slot(NULL, root, &key, path, 0, 0);
|
||||
if (ret < 0) {
|
||||
btrfs_free_path(path);
|
||||
return ret;
|
||||
} else if (ret > 0) {
|
||||
if (inode->i_ino == BTRFS_FIRST_FREE_OBJECTID) {
|
||||
path->slots[0]--;
|
||||
} else {
|
||||
btrfs_free_path(path);
|
||||
return -ENOENT;
|
||||
}
|
||||
}
|
||||
leaf = path->nodes[0];
|
||||
|
||||
if (inode->i_ino == BTRFS_FIRST_FREE_OBJECTID) {
|
||||
rref = btrfs_item_ptr(leaf, path->slots[0],
|
||||
struct btrfs_root_ref);
|
||||
name_ptr = (unsigned long)(rref + 1);
|
||||
name_len = btrfs_root_ref_name_len(leaf, rref);
|
||||
} else {
|
||||
iref = btrfs_item_ptr(leaf, path->slots[0],
|
||||
struct btrfs_inode_ref);
|
||||
name_ptr = (unsigned long)(iref + 1);
|
||||
name_len = btrfs_inode_ref_name_len(leaf, iref);
|
||||
}
|
||||
|
||||
read_extent_buffer(leaf, name, name_ptr, name_len);
|
||||
btrfs_free_path(path);
|
||||
|
||||
/*
|
||||
* have to add the null termination to make sure that reconnect_path
|
||||
* gets the right len for strlen
|
||||
*/
|
||||
name[name_len] = '\0';
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
const struct export_operations btrfs_export_ops = {
|
||||
.encode_fh = btrfs_encode_fh,
|
||||
.fh_to_dentry = btrfs_fh_to_dentry,
|
||||
.fh_to_parent = btrfs_fh_to_parent,
|
||||
.get_parent = btrfs_get_parent,
|
||||
.get_name = btrfs_get_name,
|
||||
};
|
||||
|
|
|
@ -3412,7 +3412,7 @@ again:
|
|||
* our reservation.
|
||||
*/
|
||||
if (unused <= space_info->total_bytes) {
|
||||
unused -= space_info->total_bytes;
|
||||
unused = space_info->total_bytes - unused;
|
||||
if (unused >= num_bytes) {
|
||||
if (!reserved)
|
||||
space_info->bytes_reserved += orig_bytes;
|
||||
|
|
|
@ -1828,9 +1828,9 @@ static void end_bio_extent_preparewrite(struct bio *bio, int err)
|
|||
bio_put(bio);
|
||||
}
|
||||
|
||||
static struct bio *
|
||||
extent_bio_alloc(struct block_device *bdev, u64 first_sector, int nr_vecs,
|
||||
gfp_t gfp_flags)
|
||||
struct bio *
|
||||
btrfs_bio_alloc(struct block_device *bdev, u64 first_sector, int nr_vecs,
|
||||
gfp_t gfp_flags)
|
||||
{
|
||||
struct bio *bio;
|
||||
|
||||
|
@ -1919,7 +1919,7 @@ static int submit_extent_page(int rw, struct extent_io_tree *tree,
|
|||
else
|
||||
nr = bio_get_nr_vecs(bdev);
|
||||
|
||||
bio = extent_bio_alloc(bdev, sector, nr, GFP_NOFS | __GFP_HIGH);
|
||||
bio = btrfs_bio_alloc(bdev, sector, nr, GFP_NOFS | __GFP_HIGH);
|
||||
|
||||
bio_add_page(bio, page, page_size, offset);
|
||||
bio->bi_end_io = end_io_func;
|
||||
|
@ -2901,21 +2901,53 @@ out:
|
|||
int extent_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo,
|
||||
__u64 start, __u64 len, get_extent_t *get_extent)
|
||||
{
|
||||
int ret;
|
||||
int ret = 0;
|
||||
u64 off = start;
|
||||
u64 max = start + len;
|
||||
u32 flags = 0;
|
||||
u32 found_type;
|
||||
u64 last;
|
||||
u64 disko = 0;
|
||||
struct btrfs_key found_key;
|
||||
struct extent_map *em = NULL;
|
||||
struct extent_state *cached_state = NULL;
|
||||
struct btrfs_path *path;
|
||||
struct btrfs_file_extent_item *item;
|
||||
int end = 0;
|
||||
u64 em_start = 0, em_len = 0;
|
||||
unsigned long emflags;
|
||||
ret = 0;
|
||||
int hole = 0;
|
||||
|
||||
if (len == 0)
|
||||
return -EINVAL;
|
||||
|
||||
path = btrfs_alloc_path();
|
||||
if (!path)
|
||||
return -ENOMEM;
|
||||
path->leave_spinning = 1;
|
||||
|
||||
ret = btrfs_lookup_file_extent(NULL, BTRFS_I(inode)->root,
|
||||
path, inode->i_ino, -1, 0);
|
||||
if (ret < 0) {
|
||||
btrfs_free_path(path);
|
||||
return ret;
|
||||
}
|
||||
WARN_ON(!ret);
|
||||
path->slots[0]--;
|
||||
item = btrfs_item_ptr(path->nodes[0], path->slots[0],
|
||||
struct btrfs_file_extent_item);
|
||||
btrfs_item_key_to_cpu(path->nodes[0], &found_key, path->slots[0]);
|
||||
found_type = btrfs_key_type(&found_key);
|
||||
|
||||
/* No extents, just return */
|
||||
if (found_key.objectid != inode->i_ino ||
|
||||
found_type != BTRFS_EXTENT_DATA_KEY) {
|
||||
btrfs_free_path(path);
|
||||
return 0;
|
||||
}
|
||||
last = found_key.offset;
|
||||
btrfs_free_path(path);
|
||||
|
||||
lock_extent_bits(&BTRFS_I(inode)->io_tree, start, start + len, 0,
|
||||
&cached_state, GFP_NOFS);
|
||||
em = get_extent(inode, NULL, 0, off, max - off, 0);
|
||||
|
@ -2925,11 +2957,18 @@ int extent_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo,
|
|||
ret = PTR_ERR(em);
|
||||
goto out;
|
||||
}
|
||||
|
||||
while (!end) {
|
||||
hole = 0;
|
||||
off = em->start + em->len;
|
||||
if (off >= max)
|
||||
end = 1;
|
||||
|
||||
if (em->block_start == EXTENT_MAP_HOLE) {
|
||||
hole = 1;
|
||||
goto next;
|
||||
}
|
||||
|
||||
em_start = em->start;
|
||||
em_len = em->len;
|
||||
|
||||
|
@ -2939,8 +2978,6 @@ int extent_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo,
|
|||
if (em->block_start == EXTENT_MAP_LAST_BYTE) {
|
||||
end = 1;
|
||||
flags |= FIEMAP_EXTENT_LAST;
|
||||
} else if (em->block_start == EXTENT_MAP_HOLE) {
|
||||
flags |= FIEMAP_EXTENT_UNWRITTEN;
|
||||
} else if (em->block_start == EXTENT_MAP_INLINE) {
|
||||
flags |= (FIEMAP_EXTENT_DATA_INLINE |
|
||||
FIEMAP_EXTENT_NOT_ALIGNED);
|
||||
|
@ -2953,10 +2990,10 @@ int extent_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo,
|
|||
if (test_bit(EXTENT_FLAG_COMPRESSED, &em->flags))
|
||||
flags |= FIEMAP_EXTENT_ENCODED;
|
||||
|
||||
next:
|
||||
emflags = em->flags;
|
||||
free_extent_map(em);
|
||||
em = NULL;
|
||||
|
||||
if (!end) {
|
||||
em = get_extent(inode, NULL, 0, off, max - off, 0);
|
||||
if (!em)
|
||||
|
@ -2967,15 +3004,23 @@ int extent_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo,
|
|||
}
|
||||
emflags = em->flags;
|
||||
}
|
||||
|
||||
if (test_bit(EXTENT_FLAG_VACANCY, &emflags)) {
|
||||
flags |= FIEMAP_EXTENT_LAST;
|
||||
end = 1;
|
||||
}
|
||||
|
||||
ret = fiemap_fill_next_extent(fieinfo, em_start, disko,
|
||||
em_len, flags);
|
||||
if (ret)
|
||||
goto out_free;
|
||||
if (em_start == last) {
|
||||
flags |= FIEMAP_EXTENT_LAST;
|
||||
end = 1;
|
||||
}
|
||||
|
||||
if (!hole) {
|
||||
ret = fiemap_fill_next_extent(fieinfo, em_start, disko,
|
||||
em_len, flags);
|
||||
if (ret)
|
||||
goto out_free;
|
||||
}
|
||||
}
|
||||
out_free:
|
||||
free_extent_map(em);
|
||||
|
@ -3836,8 +3881,10 @@ int try_release_extent_buffer(struct extent_io_tree *tree, struct page *page)
|
|||
|
||||
spin_lock(&tree->buffer_lock);
|
||||
eb = radix_tree_lookup(&tree->buffer, start >> PAGE_CACHE_SHIFT);
|
||||
if (!eb)
|
||||
goto out;
|
||||
if (!eb) {
|
||||
spin_unlock(&tree->buffer_lock);
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (test_bit(EXTENT_BUFFER_DIRTY, &eb->bflags)) {
|
||||
ret = 0;
|
||||
|
|
|
@ -310,4 +310,7 @@ int extent_clear_unlock_delalloc(struct inode *inode,
|
|||
struct extent_io_tree *tree,
|
||||
u64 start, u64 end, struct page *locked_page,
|
||||
unsigned long op);
|
||||
struct bio *
|
||||
btrfs_bio_alloc(struct block_device *bdev, u64 first_sector, int nr_vecs,
|
||||
gfp_t gfp_flags);
|
||||
#endif
|
||||
|
|
|
@ -1047,8 +1047,14 @@ out:
|
|||
|
||||
if ((file->f_flags & O_DSYNC) || IS_SYNC(inode)) {
|
||||
trans = btrfs_start_transaction(root, 0);
|
||||
if (IS_ERR(trans)) {
|
||||
num_written = PTR_ERR(trans);
|
||||
goto done;
|
||||
}
|
||||
mutex_lock(&inode->i_mutex);
|
||||
ret = btrfs_log_dentry_safe(trans, root,
|
||||
file->f_dentry);
|
||||
mutex_unlock(&inode->i_mutex);
|
||||
if (ret == 0) {
|
||||
ret = btrfs_sync_log(trans, root);
|
||||
if (ret == 0)
|
||||
|
@ -1067,6 +1073,7 @@ out:
|
|||
(start_pos + num_written - 1) >> PAGE_CACHE_SHIFT);
|
||||
}
|
||||
}
|
||||
done:
|
||||
current->backing_dev_info = NULL;
|
||||
return num_written ? num_written : err;
|
||||
}
|
||||
|
|
294
fs/btrfs/inode.c
294
fs/btrfs/inode.c
|
@ -4501,6 +4501,7 @@ static struct inode *btrfs_new_inode(struct btrfs_trans_handle *trans,
|
|||
BTRFS_I(inode)->index_cnt = 2;
|
||||
BTRFS_I(inode)->root = root;
|
||||
BTRFS_I(inode)->generation = trans->transid;
|
||||
inode->i_generation = BTRFS_I(inode)->generation;
|
||||
btrfs_set_inode_space_info(root, inode);
|
||||
|
||||
if (mode & S_IFDIR)
|
||||
|
@ -4622,12 +4623,12 @@ int btrfs_add_link(struct btrfs_trans_handle *trans,
|
|||
}
|
||||
|
||||
static int btrfs_add_nondir(struct btrfs_trans_handle *trans,
|
||||
struct dentry *dentry, struct inode *inode,
|
||||
int backref, u64 index)
|
||||
struct inode *dir, struct dentry *dentry,
|
||||
struct inode *inode, int backref, u64 index)
|
||||
{
|
||||
int err = btrfs_add_link(trans, dentry->d_parent->d_inode,
|
||||
inode, dentry->d_name.name,
|
||||
dentry->d_name.len, backref, index);
|
||||
int err = btrfs_add_link(trans, dir, inode,
|
||||
dentry->d_name.name, dentry->d_name.len,
|
||||
backref, index);
|
||||
if (!err) {
|
||||
d_instantiate(dentry, inode);
|
||||
return 0;
|
||||
|
@ -4668,8 +4669,7 @@ static int btrfs_mknod(struct inode *dir, struct dentry *dentry,
|
|||
btrfs_set_trans_block_group(trans, dir);
|
||||
|
||||
inode = btrfs_new_inode(trans, root, dir, dentry->d_name.name,
|
||||
dentry->d_name.len,
|
||||
dentry->d_parent->d_inode->i_ino, objectid,
|
||||
dentry->d_name.len, dir->i_ino, objectid,
|
||||
BTRFS_I(dir)->block_group, mode, &index);
|
||||
err = PTR_ERR(inode);
|
||||
if (IS_ERR(inode))
|
||||
|
@ -4682,7 +4682,7 @@ static int btrfs_mknod(struct inode *dir, struct dentry *dentry,
|
|||
}
|
||||
|
||||
btrfs_set_trans_block_group(trans, inode);
|
||||
err = btrfs_add_nondir(trans, dentry, inode, 0, index);
|
||||
err = btrfs_add_nondir(trans, dir, dentry, inode, 0, index);
|
||||
if (err)
|
||||
drop_inode = 1;
|
||||
else {
|
||||
|
@ -4730,10 +4730,8 @@ static int btrfs_create(struct inode *dir, struct dentry *dentry,
|
|||
btrfs_set_trans_block_group(trans, dir);
|
||||
|
||||
inode = btrfs_new_inode(trans, root, dir, dentry->d_name.name,
|
||||
dentry->d_name.len,
|
||||
dentry->d_parent->d_inode->i_ino,
|
||||
objectid, BTRFS_I(dir)->block_group, mode,
|
||||
&index);
|
||||
dentry->d_name.len, dir->i_ino, objectid,
|
||||
BTRFS_I(dir)->block_group, mode, &index);
|
||||
err = PTR_ERR(inode);
|
||||
if (IS_ERR(inode))
|
||||
goto out_unlock;
|
||||
|
@ -4745,7 +4743,7 @@ static int btrfs_create(struct inode *dir, struct dentry *dentry,
|
|||
}
|
||||
|
||||
btrfs_set_trans_block_group(trans, inode);
|
||||
err = btrfs_add_nondir(trans, dentry, inode, 0, index);
|
||||
err = btrfs_add_nondir(trans, dir, dentry, inode, 0, index);
|
||||
if (err)
|
||||
drop_inode = 1;
|
||||
else {
|
||||
|
@ -4787,6 +4785,7 @@ static int btrfs_link(struct dentry *old_dentry, struct inode *dir,
|
|||
return -EPERM;
|
||||
|
||||
btrfs_inc_nlink(inode);
|
||||
inode->i_ctime = CURRENT_TIME;
|
||||
|
||||
err = btrfs_set_inode_index(dir, &index);
|
||||
if (err)
|
||||
|
@ -4805,15 +4804,17 @@ static int btrfs_link(struct dentry *old_dentry, struct inode *dir,
|
|||
btrfs_set_trans_block_group(trans, dir);
|
||||
ihold(inode);
|
||||
|
||||
err = btrfs_add_nondir(trans, dentry, inode, 1, index);
|
||||
err = btrfs_add_nondir(trans, dir, dentry, inode, 1, index);
|
||||
|
||||
if (err) {
|
||||
drop_inode = 1;
|
||||
} else {
|
||||
struct dentry *parent = dget_parent(dentry);
|
||||
btrfs_update_inode_block_group(trans, dir);
|
||||
err = btrfs_update_inode(trans, root, inode);
|
||||
BUG_ON(err);
|
||||
btrfs_log_new_name(trans, inode, NULL, dentry->d_parent);
|
||||
btrfs_log_new_name(trans, inode, NULL, parent);
|
||||
dput(parent);
|
||||
}
|
||||
|
||||
nr = trans->blocks_used;
|
||||
|
@ -4853,8 +4854,7 @@ static int btrfs_mkdir(struct inode *dir, struct dentry *dentry, int mode)
|
|||
btrfs_set_trans_block_group(trans, dir);
|
||||
|
||||
inode = btrfs_new_inode(trans, root, dir, dentry->d_name.name,
|
||||
dentry->d_name.len,
|
||||
dentry->d_parent->d_inode->i_ino, objectid,
|
||||
dentry->d_name.len, dir->i_ino, objectid,
|
||||
BTRFS_I(dir)->block_group, S_IFDIR | mode,
|
||||
&index);
|
||||
if (IS_ERR(inode)) {
|
||||
|
@ -4877,9 +4877,8 @@ static int btrfs_mkdir(struct inode *dir, struct dentry *dentry, int mode)
|
|||
if (err)
|
||||
goto out_fail;
|
||||
|
||||
err = btrfs_add_link(trans, dentry->d_parent->d_inode,
|
||||
inode, dentry->d_name.name,
|
||||
dentry->d_name.len, 0, index);
|
||||
err = btrfs_add_link(trans, dir, inode, dentry->d_name.name,
|
||||
dentry->d_name.len, 0, index);
|
||||
if (err)
|
||||
goto out_fail;
|
||||
|
||||
|
@ -5535,13 +5534,21 @@ struct btrfs_dio_private {
|
|||
u64 bytes;
|
||||
u32 *csums;
|
||||
void *private;
|
||||
|
||||
/* number of bios pending for this dio */
|
||||
atomic_t pending_bios;
|
||||
|
||||
/* IO errors */
|
||||
int errors;
|
||||
|
||||
struct bio *orig_bio;
|
||||
};
|
||||
|
||||
static void btrfs_endio_direct_read(struct bio *bio, int err)
|
||||
{
|
||||
struct btrfs_dio_private *dip = bio->bi_private;
|
||||
struct bio_vec *bvec_end = bio->bi_io_vec + bio->bi_vcnt - 1;
|
||||
struct bio_vec *bvec = bio->bi_io_vec;
|
||||
struct btrfs_dio_private *dip = bio->bi_private;
|
||||
struct inode *inode = dip->inode;
|
||||
struct btrfs_root *root = BTRFS_I(inode)->root;
|
||||
u64 start;
|
||||
|
@ -5595,15 +5602,18 @@ static void btrfs_endio_direct_write(struct bio *bio, int err)
|
|||
struct btrfs_trans_handle *trans;
|
||||
struct btrfs_ordered_extent *ordered = NULL;
|
||||
struct extent_state *cached_state = NULL;
|
||||
u64 ordered_offset = dip->logical_offset;
|
||||
u64 ordered_bytes = dip->bytes;
|
||||
int ret;
|
||||
|
||||
if (err)
|
||||
goto out_done;
|
||||
|
||||
ret = btrfs_dec_test_ordered_pending(inode, &ordered,
|
||||
dip->logical_offset, dip->bytes);
|
||||
again:
|
||||
ret = btrfs_dec_test_first_ordered_pending(inode, &ordered,
|
||||
&ordered_offset,
|
||||
ordered_bytes);
|
||||
if (!ret)
|
||||
goto out_done;
|
||||
goto out_test;
|
||||
|
||||
BUG_ON(!ordered);
|
||||
|
||||
|
@ -5663,8 +5673,20 @@ out_unlock:
|
|||
out:
|
||||
btrfs_delalloc_release_metadata(inode, ordered->len);
|
||||
btrfs_end_transaction(trans, root);
|
||||
ordered_offset = ordered->file_offset + ordered->len;
|
||||
btrfs_put_ordered_extent(ordered);
|
||||
btrfs_put_ordered_extent(ordered);
|
||||
|
||||
out_test:
|
||||
/*
|
||||
* our bio might span multiple ordered extents. If we haven't
|
||||
* completed the accounting for the whole dio, go back and try again
|
||||
*/
|
||||
if (ordered_offset < dip->logical_offset + dip->bytes) {
|
||||
ordered_bytes = dip->logical_offset + dip->bytes -
|
||||
ordered_offset;
|
||||
goto again;
|
||||
}
|
||||
out_done:
|
||||
bio->bi_private = dip->private;
|
||||
|
||||
|
@ -5684,6 +5706,176 @@ static int __btrfs_submit_bio_start_direct_io(struct inode *inode, int rw,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static void btrfs_end_dio_bio(struct bio *bio, int err)
|
||||
{
|
||||
struct btrfs_dio_private *dip = bio->bi_private;
|
||||
|
||||
if (err) {
|
||||
printk(KERN_ERR "btrfs direct IO failed ino %lu rw %lu "
|
||||
"disk_bytenr %lu len %u err no %d\n",
|
||||
dip->inode->i_ino, bio->bi_rw, bio->bi_sector,
|
||||
bio->bi_size, err);
|
||||
dip->errors = 1;
|
||||
|
||||
/*
|
||||
* before atomic variable goto zero, we must make sure
|
||||
* dip->errors is perceived to be set.
|
||||
*/
|
||||
smp_mb__before_atomic_dec();
|
||||
}
|
||||
|
||||
/* if there are more bios still pending for this dio, just exit */
|
||||
if (!atomic_dec_and_test(&dip->pending_bios))
|
||||
goto out;
|
||||
|
||||
if (dip->errors)
|
||||
bio_io_error(dip->orig_bio);
|
||||
else {
|
||||
set_bit(BIO_UPTODATE, &dip->orig_bio->bi_flags);
|
||||
bio_endio(dip->orig_bio, 0);
|
||||
}
|
||||
out:
|
||||
bio_put(bio);
|
||||
}
|
||||
|
||||
static struct bio *btrfs_dio_bio_alloc(struct block_device *bdev,
|
||||
u64 first_sector, gfp_t gfp_flags)
|
||||
{
|
||||
int nr_vecs = bio_get_nr_vecs(bdev);
|
||||
return btrfs_bio_alloc(bdev, first_sector, nr_vecs, gfp_flags);
|
||||
}
|
||||
|
||||
static inline int __btrfs_submit_dio_bio(struct bio *bio, struct inode *inode,
|
||||
int rw, u64 file_offset, int skip_sum,
|
||||
u32 *csums)
|
||||
{
|
||||
int write = rw & REQ_WRITE;
|
||||
struct btrfs_root *root = BTRFS_I(inode)->root;
|
||||
int ret;
|
||||
|
||||
bio_get(bio);
|
||||
ret = btrfs_bio_wq_end_io(root->fs_info, bio, 0);
|
||||
if (ret)
|
||||
goto err;
|
||||
|
||||
if (write && !skip_sum) {
|
||||
ret = btrfs_wq_submit_bio(root->fs_info,
|
||||
inode, rw, bio, 0, 0,
|
||||
file_offset,
|
||||
__btrfs_submit_bio_start_direct_io,
|
||||
__btrfs_submit_bio_done);
|
||||
goto err;
|
||||
} else if (!skip_sum)
|
||||
btrfs_lookup_bio_sums_dio(root, inode, bio,
|
||||
file_offset, csums);
|
||||
|
||||
ret = btrfs_map_bio(root, rw, bio, 0, 1);
|
||||
err:
|
||||
bio_put(bio);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int btrfs_submit_direct_hook(int rw, struct btrfs_dio_private *dip,
|
||||
int skip_sum)
|
||||
{
|
||||
struct inode *inode = dip->inode;
|
||||
struct btrfs_root *root = BTRFS_I(inode)->root;
|
||||
struct btrfs_mapping_tree *map_tree = &root->fs_info->mapping_tree;
|
||||
struct bio *bio;
|
||||
struct bio *orig_bio = dip->orig_bio;
|
||||
struct bio_vec *bvec = orig_bio->bi_io_vec;
|
||||
u64 start_sector = orig_bio->bi_sector;
|
||||
u64 file_offset = dip->logical_offset;
|
||||
u64 submit_len = 0;
|
||||
u64 map_length;
|
||||
int nr_pages = 0;
|
||||
u32 *csums = dip->csums;
|
||||
int ret = 0;
|
||||
|
||||
bio = btrfs_dio_bio_alloc(orig_bio->bi_bdev, start_sector, GFP_NOFS);
|
||||
if (!bio)
|
||||
return -ENOMEM;
|
||||
bio->bi_private = dip;
|
||||
bio->bi_end_io = btrfs_end_dio_bio;
|
||||
atomic_inc(&dip->pending_bios);
|
||||
|
||||
map_length = orig_bio->bi_size;
|
||||
ret = btrfs_map_block(map_tree, READ, start_sector << 9,
|
||||
&map_length, NULL, 0);
|
||||
if (ret) {
|
||||
bio_put(bio);
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
while (bvec <= (orig_bio->bi_io_vec + orig_bio->bi_vcnt - 1)) {
|
||||
if (unlikely(map_length < submit_len + bvec->bv_len ||
|
||||
bio_add_page(bio, bvec->bv_page, bvec->bv_len,
|
||||
bvec->bv_offset) < bvec->bv_len)) {
|
||||
/*
|
||||
* inc the count before we submit the bio so
|
||||
* we know the end IO handler won't happen before
|
||||
* we inc the count. Otherwise, the dip might get freed
|
||||
* before we're done setting it up
|
||||
*/
|
||||
atomic_inc(&dip->pending_bios);
|
||||
ret = __btrfs_submit_dio_bio(bio, inode, rw,
|
||||
file_offset, skip_sum,
|
||||
csums);
|
||||
if (ret) {
|
||||
bio_put(bio);
|
||||
atomic_dec(&dip->pending_bios);
|
||||
goto out_err;
|
||||
}
|
||||
|
||||
if (!skip_sum)
|
||||
csums = csums + nr_pages;
|
||||
start_sector += submit_len >> 9;
|
||||
file_offset += submit_len;
|
||||
|
||||
submit_len = 0;
|
||||
nr_pages = 0;
|
||||
|
||||
bio = btrfs_dio_bio_alloc(orig_bio->bi_bdev,
|
||||
start_sector, GFP_NOFS);
|
||||
if (!bio)
|
||||
goto out_err;
|
||||
bio->bi_private = dip;
|
||||
bio->bi_end_io = btrfs_end_dio_bio;
|
||||
|
||||
map_length = orig_bio->bi_size;
|
||||
ret = btrfs_map_block(map_tree, READ, start_sector << 9,
|
||||
&map_length, NULL, 0);
|
||||
if (ret) {
|
||||
bio_put(bio);
|
||||
goto out_err;
|
||||
}
|
||||
} else {
|
||||
submit_len += bvec->bv_len;
|
||||
nr_pages ++;
|
||||
bvec++;
|
||||
}
|
||||
}
|
||||
|
||||
ret = __btrfs_submit_dio_bio(bio, inode, rw, file_offset, skip_sum,
|
||||
csums);
|
||||
if (!ret)
|
||||
return 0;
|
||||
|
||||
bio_put(bio);
|
||||
out_err:
|
||||
dip->errors = 1;
|
||||
/*
|
||||
* before atomic variable goto zero, we must
|
||||
* make sure dip->errors is perceived to be set.
|
||||
*/
|
||||
smp_mb__before_atomic_dec();
|
||||
if (atomic_dec_and_test(&dip->pending_bios))
|
||||
bio_io_error(dip->orig_bio);
|
||||
|
||||
/* bio_end_io() will handle error, so we needn't return it */
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void btrfs_submit_direct(int rw, struct bio *bio, struct inode *inode,
|
||||
loff_t file_offset)
|
||||
{
|
||||
|
@ -5723,36 +5915,18 @@ static void btrfs_submit_direct(int rw, struct bio *bio, struct inode *inode,
|
|||
|
||||
dip->disk_bytenr = (u64)bio->bi_sector << 9;
|
||||
bio->bi_private = dip;
|
||||
dip->errors = 0;
|
||||
dip->orig_bio = bio;
|
||||
atomic_set(&dip->pending_bios, 0);
|
||||
|
||||
if (write)
|
||||
bio->bi_end_io = btrfs_endio_direct_write;
|
||||
else
|
||||
bio->bi_end_io = btrfs_endio_direct_read;
|
||||
|
||||
ret = btrfs_bio_wq_end_io(root->fs_info, bio, 0);
|
||||
if (ret)
|
||||
goto out_err;
|
||||
|
||||
if (write && !skip_sum) {
|
||||
ret = btrfs_wq_submit_bio(BTRFS_I(inode)->root->fs_info,
|
||||
inode, rw, bio, 0, 0,
|
||||
dip->logical_offset,
|
||||
__btrfs_submit_bio_start_direct_io,
|
||||
__btrfs_submit_bio_done);
|
||||
if (ret)
|
||||
goto out_err;
|
||||
ret = btrfs_submit_direct_hook(rw, dip, skip_sum);
|
||||
if (!ret)
|
||||
return;
|
||||
} else if (!skip_sum)
|
||||
btrfs_lookup_bio_sums_dio(root, inode, bio,
|
||||
dip->logical_offset, dip->csums);
|
||||
|
||||
ret = btrfs_map_bio(root, rw, bio, 0, 1);
|
||||
if (ret)
|
||||
goto out_err;
|
||||
return;
|
||||
out_err:
|
||||
kfree(dip->csums);
|
||||
kfree(dip);
|
||||
free_ordered:
|
||||
/*
|
||||
* If this is a write, we need to clean up the reserved space and kill
|
||||
|
@ -6607,8 +6781,9 @@ static int btrfs_rename(struct inode *old_dir, struct dentry *old_dentry,
|
|||
BUG_ON(ret);
|
||||
|
||||
if (old_inode->i_ino != BTRFS_FIRST_FREE_OBJECTID) {
|
||||
btrfs_log_new_name(trans, old_inode, old_dir,
|
||||
new_dentry->d_parent);
|
||||
struct dentry *parent = dget_parent(new_dentry);
|
||||
btrfs_log_new_name(trans, old_inode, old_dir, parent);
|
||||
dput(parent);
|
||||
btrfs_end_log_trans(root);
|
||||
}
|
||||
out_fail:
|
||||
|
@ -6758,8 +6933,7 @@ static int btrfs_symlink(struct inode *dir, struct dentry *dentry,
|
|||
btrfs_set_trans_block_group(trans, dir);
|
||||
|
||||
inode = btrfs_new_inode(trans, root, dir, dentry->d_name.name,
|
||||
dentry->d_name.len,
|
||||
dentry->d_parent->d_inode->i_ino, objectid,
|
||||
dentry->d_name.len, dir->i_ino, objectid,
|
||||
BTRFS_I(dir)->block_group, S_IFLNK|S_IRWXUGO,
|
||||
&index);
|
||||
err = PTR_ERR(inode);
|
||||
|
@ -6773,7 +6947,7 @@ static int btrfs_symlink(struct inode *dir, struct dentry *dentry,
|
|||
}
|
||||
|
||||
btrfs_set_trans_block_group(trans, inode);
|
||||
err = btrfs_add_nondir(trans, dentry, inode, 0, index);
|
||||
err = btrfs_add_nondir(trans, dir, dentry, inode, 0, index);
|
||||
if (err)
|
||||
drop_inode = 1;
|
||||
else {
|
||||
|
@ -6844,6 +7018,7 @@ static int __btrfs_prealloc_file_range(struct inode *inode, int mode,
|
|||
struct btrfs_root *root = BTRFS_I(inode)->root;
|
||||
struct btrfs_key ins;
|
||||
u64 cur_offset = start;
|
||||
u64 i_size;
|
||||
int ret = 0;
|
||||
bool own_trans = true;
|
||||
|
||||
|
@ -6885,11 +7060,11 @@ static int __btrfs_prealloc_file_range(struct inode *inode, int mode,
|
|||
(actual_len > inode->i_size) &&
|
||||
(cur_offset > inode->i_size)) {
|
||||
if (cur_offset > actual_len)
|
||||
i_size_write(inode, actual_len);
|
||||
i_size = actual_len;
|
||||
else
|
||||
i_size_write(inode, cur_offset);
|
||||
i_size_write(inode, cur_offset);
|
||||
btrfs_ordered_update_i_size(inode, cur_offset, NULL);
|
||||
i_size = cur_offset;
|
||||
i_size_write(inode, i_size);
|
||||
btrfs_ordered_update_i_size(inode, i_size, NULL);
|
||||
}
|
||||
|
||||
ret = btrfs_update_inode(trans, root, inode);
|
||||
|
@ -6943,6 +7118,10 @@ static long btrfs_fallocate(struct inode *inode, int mode,
|
|||
btrfs_wait_ordered_range(inode, alloc_start, alloc_end - alloc_start);
|
||||
|
||||
mutex_lock(&inode->i_mutex);
|
||||
ret = inode_newsize_ok(inode, alloc_end);
|
||||
if (ret)
|
||||
goto out;
|
||||
|
||||
if (alloc_start > inode->i_size) {
|
||||
ret = btrfs_cont_expand(inode, alloc_start);
|
||||
if (ret)
|
||||
|
@ -7139,6 +7318,7 @@ static const struct inode_operations btrfs_symlink_inode_operations = {
|
|||
.readlink = generic_readlink,
|
||||
.follow_link = page_follow_link_light,
|
||||
.put_link = page_put_link,
|
||||
.getattr = btrfs_getattr,
|
||||
.permission = btrfs_permission,
|
||||
.setxattr = btrfs_setxattr,
|
||||
.getxattr = btrfs_getxattr,
|
||||
|
|
|
@ -233,7 +233,8 @@ static noinline int create_subvol(struct btrfs_root *root,
|
|||
struct btrfs_inode_item *inode_item;
|
||||
struct extent_buffer *leaf;
|
||||
struct btrfs_root *new_root;
|
||||
struct inode *dir = dentry->d_parent->d_inode;
|
||||
struct dentry *parent = dget_parent(dentry);
|
||||
struct inode *dir;
|
||||
int ret;
|
||||
int err;
|
||||
u64 objectid;
|
||||
|
@ -242,8 +243,13 @@ static noinline int create_subvol(struct btrfs_root *root,
|
|||
|
||||
ret = btrfs_find_free_objectid(NULL, root->fs_info->tree_root,
|
||||
0, &objectid);
|
||||
if (ret)
|
||||
if (ret) {
|
||||
dput(parent);
|
||||
return ret;
|
||||
}
|
||||
|
||||
dir = parent->d_inode;
|
||||
|
||||
/*
|
||||
* 1 - inode item
|
||||
* 2 - refs
|
||||
|
@ -251,8 +257,10 @@ static noinline int create_subvol(struct btrfs_root *root,
|
|||
* 2 - dir items
|
||||
*/
|
||||
trans = btrfs_start_transaction(root, 6);
|
||||
if (IS_ERR(trans))
|
||||
if (IS_ERR(trans)) {
|
||||
dput(parent);
|
||||
return PTR_ERR(trans);
|
||||
}
|
||||
|
||||
leaf = btrfs_alloc_free_block(trans, root, root->leafsize,
|
||||
0, objectid, NULL, 0, 0, 0);
|
||||
|
@ -339,6 +347,7 @@ static noinline int create_subvol(struct btrfs_root *root,
|
|||
|
||||
d_instantiate(dentry, btrfs_lookup_dentry(dir, dentry));
|
||||
fail:
|
||||
dput(parent);
|
||||
if (async_transid) {
|
||||
*async_transid = trans->transid;
|
||||
err = btrfs_commit_transaction_async(trans, root, 1);
|
||||
|
@ -354,6 +363,7 @@ static int create_snapshot(struct btrfs_root *root, struct dentry *dentry,
|
|||
char *name, int namelen, u64 *async_transid)
|
||||
{
|
||||
struct inode *inode;
|
||||
struct dentry *parent;
|
||||
struct btrfs_pending_snapshot *pending_snapshot;
|
||||
struct btrfs_trans_handle *trans;
|
||||
int ret;
|
||||
|
@ -396,7 +406,9 @@ static int create_snapshot(struct btrfs_root *root, struct dentry *dentry,
|
|||
|
||||
btrfs_orphan_cleanup(pending_snapshot->snap);
|
||||
|
||||
inode = btrfs_lookup_dentry(dentry->d_parent->d_inode, dentry);
|
||||
parent = dget_parent(dentry);
|
||||
inode = btrfs_lookup_dentry(parent->d_inode, dentry);
|
||||
dput(parent);
|
||||
if (IS_ERR(inode)) {
|
||||
ret = PTR_ERR(inode);
|
||||
goto fail;
|
||||
|
@ -1669,12 +1681,11 @@ static noinline long btrfs_ioctl_clone(struct file *file, unsigned long srcfd,
|
|||
olen = len = src->i_size - off;
|
||||
/* if we extend to eof, continue to block boundary */
|
||||
if (off + len == src->i_size)
|
||||
len = ((src->i_size + bs-1) & ~(bs-1))
|
||||
- off;
|
||||
len = ALIGN(src->i_size, bs) - off;
|
||||
|
||||
/* verify the end result is block aligned */
|
||||
if ((off & (bs-1)) ||
|
||||
((off + len) & (bs-1)))
|
||||
if (!IS_ALIGNED(off, bs) || !IS_ALIGNED(off + len, bs) ||
|
||||
!IS_ALIGNED(destoff, bs))
|
||||
goto out_unlock;
|
||||
|
||||
/* do any pending delalloc/csum calc on src, one way or
|
||||
|
@ -1874,8 +1885,8 @@ static noinline long btrfs_ioctl_clone(struct file *file, unsigned long srcfd,
|
|||
* but shouldn't round up the file size
|
||||
*/
|
||||
endoff = new_key.offset + datal;
|
||||
if (endoff > off+olen)
|
||||
endoff = off+olen;
|
||||
if (endoff > destoff+olen)
|
||||
endoff = destoff+olen;
|
||||
if (endoff > inode->i_size)
|
||||
btrfs_i_size_write(inode, endoff);
|
||||
|
||||
|
|
|
@ -248,6 +248,73 @@ int btrfs_add_ordered_sum(struct inode *inode,
|
|||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* this is used to account for finished IO across a given range
|
||||
* of the file. The IO may span ordered extents. If
|
||||
* a given ordered_extent is completely done, 1 is returned, otherwise
|
||||
* 0.
|
||||
*
|
||||
* test_and_set_bit on a flag in the struct btrfs_ordered_extent is used
|
||||
* to make sure this function only returns 1 once for a given ordered extent.
|
||||
*
|
||||
* file_offset is updated to one byte past the range that is recorded as
|
||||
* complete. This allows you to walk forward in the file.
|
||||
*/
|
||||
int btrfs_dec_test_first_ordered_pending(struct inode *inode,
|
||||
struct btrfs_ordered_extent **cached,
|
||||
u64 *file_offset, u64 io_size)
|
||||
{
|
||||
struct btrfs_ordered_inode_tree *tree;
|
||||
struct rb_node *node;
|
||||
struct btrfs_ordered_extent *entry = NULL;
|
||||
int ret;
|
||||
u64 dec_end;
|
||||
u64 dec_start;
|
||||
u64 to_dec;
|
||||
|
||||
tree = &BTRFS_I(inode)->ordered_tree;
|
||||
spin_lock(&tree->lock);
|
||||
node = tree_search(tree, *file_offset);
|
||||
if (!node) {
|
||||
ret = 1;
|
||||
goto out;
|
||||
}
|
||||
|
||||
entry = rb_entry(node, struct btrfs_ordered_extent, rb_node);
|
||||
if (!offset_in_entry(entry, *file_offset)) {
|
||||
ret = 1;
|
||||
goto out;
|
||||
}
|
||||
|
||||
dec_start = max(*file_offset, entry->file_offset);
|
||||
dec_end = min(*file_offset + io_size, entry->file_offset +
|
||||
entry->len);
|
||||
*file_offset = dec_end;
|
||||
if (dec_start > dec_end) {
|
||||
printk(KERN_CRIT "bad ordering dec_start %llu end %llu\n",
|
||||
(unsigned long long)dec_start,
|
||||
(unsigned long long)dec_end);
|
||||
}
|
||||
to_dec = dec_end - dec_start;
|
||||
if (to_dec > entry->bytes_left) {
|
||||
printk(KERN_CRIT "bad ordered accounting left %llu size %llu\n",
|
||||
(unsigned long long)entry->bytes_left,
|
||||
(unsigned long long)to_dec);
|
||||
}
|
||||
entry->bytes_left -= to_dec;
|
||||
if (entry->bytes_left == 0)
|
||||
ret = test_and_set_bit(BTRFS_ORDERED_IO_DONE, &entry->flags);
|
||||
else
|
||||
ret = 1;
|
||||
out:
|
||||
if (!ret && cached && entry) {
|
||||
*cached = entry;
|
||||
atomic_inc(&entry->refs);
|
||||
}
|
||||
spin_unlock(&tree->lock);
|
||||
return ret == 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* this is used to account for finished IO across a given range
|
||||
* of the file. The IO should not span ordered extents. If
|
||||
|
|
|
@ -141,6 +141,9 @@ int btrfs_remove_ordered_extent(struct inode *inode,
|
|||
int btrfs_dec_test_ordered_pending(struct inode *inode,
|
||||
struct btrfs_ordered_extent **cached,
|
||||
u64 file_offset, u64 io_size);
|
||||
int btrfs_dec_test_first_ordered_pending(struct inode *inode,
|
||||
struct btrfs_ordered_extent **cached,
|
||||
u64 *file_offset, u64 io_size);
|
||||
int btrfs_add_ordered_extent(struct inode *inode, u64 file_offset,
|
||||
u64 start, u64 len, u64 disk_len, int type);
|
||||
int btrfs_add_ordered_extent_dio(struct inode *inode, u64 file_offset,
|
||||
|
|
|
@ -244,6 +244,7 @@ int btrfs_parse_options(struct btrfs_root *root, char *options)
|
|||
case Opt_space_cache:
|
||||
printk(KERN_INFO "btrfs: enabling disk space caching\n");
|
||||
btrfs_set_opt(info->mount_opt, SPACE_CACHE);
|
||||
break;
|
||||
case Opt_clear_cache:
|
||||
printk(KERN_INFO "btrfs: force clearing of disk cache\n");
|
||||
btrfs_set_opt(info->mount_opt, CLEAR_CACHE);
|
||||
|
@ -562,12 +563,26 @@ static int btrfs_show_options(struct seq_file *seq, struct vfsmount *vfs)
|
|||
|
||||
static int btrfs_test_super(struct super_block *s, void *data)
|
||||
{
|
||||
struct btrfs_fs_devices *test_fs_devices = data;
|
||||
struct btrfs_root *test_root = data;
|
||||
struct btrfs_root *root = btrfs_sb(s);
|
||||
|
||||
return root->fs_info->fs_devices == test_fs_devices;
|
||||
/*
|
||||
* If this super block is going away, return false as it
|
||||
* can't match as an existing super block.
|
||||
*/
|
||||
if (!atomic_read(&s->s_active))
|
||||
return 0;
|
||||
return root->fs_info->fs_devices == test_root->fs_info->fs_devices;
|
||||
}
|
||||
|
||||
static int btrfs_set_super(struct super_block *s, void *data)
|
||||
{
|
||||
s->s_fs_info = data;
|
||||
|
||||
return set_anon_super(s, data);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Find a superblock for the given device / mount point.
|
||||
*
|
||||
|
@ -581,6 +596,8 @@ static struct dentry *btrfs_mount(struct file_system_type *fs_type, int flags,
|
|||
struct super_block *s;
|
||||
struct dentry *root;
|
||||
struct btrfs_fs_devices *fs_devices = NULL;
|
||||
struct btrfs_root *tree_root = NULL;
|
||||
struct btrfs_fs_info *fs_info = NULL;
|
||||
fmode_t mode = FMODE_READ;
|
||||
char *subvol_name = NULL;
|
||||
u64 subvol_objectid = 0;
|
||||
|
@ -608,8 +625,24 @@ static struct dentry *btrfs_mount(struct file_system_type *fs_type, int flags,
|
|||
goto error_close_devices;
|
||||
}
|
||||
|
||||
/*
|
||||
* Setup a dummy root and fs_info for test/set super. This is because
|
||||
* we don't actually fill this stuff out until open_ctree, but we need
|
||||
* it for searching for existing supers, so this lets us do that and
|
||||
* then open_ctree will properly initialize everything later.
|
||||
*/
|
||||
fs_info = kzalloc(sizeof(struct btrfs_fs_info), GFP_NOFS);
|
||||
tree_root = kzalloc(sizeof(struct btrfs_root), GFP_NOFS);
|
||||
if (!fs_info || !tree_root) {
|
||||
error = -ENOMEM;
|
||||
goto error_close_devices;
|
||||
}
|
||||
fs_info->tree_root = tree_root;
|
||||
fs_info->fs_devices = fs_devices;
|
||||
tree_root->fs_info = fs_info;
|
||||
|
||||
bdev = fs_devices->latest_bdev;
|
||||
s = sget(fs_type, btrfs_test_super, set_anon_super, fs_devices);
|
||||
s = sget(fs_type, btrfs_test_super, btrfs_set_super, tree_root);
|
||||
if (IS_ERR(s))
|
||||
goto error_s;
|
||||
|
||||
|
@ -675,6 +708,8 @@ error_s:
|
|||
error = PTR_ERR(s);
|
||||
error_close_devices:
|
||||
btrfs_close_devices(fs_devices);
|
||||
kfree(fs_info);
|
||||
kfree(tree_root);
|
||||
error_free_subvol_name:
|
||||
kfree(subvol_name);
|
||||
return ERR_PTR(error);
|
||||
|
|
|
@ -902,6 +902,7 @@ static noinline int create_pending_snapshot(struct btrfs_trans_handle *trans,
|
|||
struct btrfs_root *root = pending->root;
|
||||
struct btrfs_root *parent_root;
|
||||
struct inode *parent_inode;
|
||||
struct dentry *parent;
|
||||
struct dentry *dentry;
|
||||
struct extent_buffer *tmp;
|
||||
struct extent_buffer *old;
|
||||
|
@ -941,7 +942,8 @@ static noinline int create_pending_snapshot(struct btrfs_trans_handle *trans,
|
|||
trans->block_rsv = &pending->block_rsv;
|
||||
|
||||
dentry = pending->dentry;
|
||||
parent_inode = dentry->d_parent->d_inode;
|
||||
parent = dget_parent(dentry);
|
||||
parent_inode = parent->d_inode;
|
||||
parent_root = BTRFS_I(parent_inode)->root;
|
||||
record_root_in_trans(trans, parent_root);
|
||||
|
||||
|
@ -989,6 +991,7 @@ static noinline int create_pending_snapshot(struct btrfs_trans_handle *trans,
|
|||
parent_inode->i_ino, index,
|
||||
dentry->d_name.name, dentry->d_name.len);
|
||||
BUG_ON(ret);
|
||||
dput(parent);
|
||||
|
||||
key.offset = (u64)-1;
|
||||
pending->snap = btrfs_read_fs_root_no_name(root->fs_info, &key);
|
||||
|
|
|
@ -2869,6 +2869,7 @@ static noinline int check_parent_dirs_for_sync(struct btrfs_trans_handle *trans,
|
|||
{
|
||||
int ret = 0;
|
||||
struct btrfs_root *root;
|
||||
struct dentry *old_parent = NULL;
|
||||
|
||||
/*
|
||||
* for regular files, if its inode is already on disk, we don't
|
||||
|
@ -2910,10 +2911,13 @@ static noinline int check_parent_dirs_for_sync(struct btrfs_trans_handle *trans,
|
|||
if (IS_ROOT(parent))
|
||||
break;
|
||||
|
||||
parent = parent->d_parent;
|
||||
parent = dget_parent(parent);
|
||||
dput(old_parent);
|
||||
old_parent = parent;
|
||||
inode = parent->d_inode;
|
||||
|
||||
}
|
||||
dput(old_parent);
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
|
@ -2945,6 +2949,7 @@ int btrfs_log_inode_parent(struct btrfs_trans_handle *trans,
|
|||
{
|
||||
int inode_only = exists_only ? LOG_INODE_EXISTS : LOG_INODE_ALL;
|
||||
struct super_block *sb;
|
||||
struct dentry *old_parent = NULL;
|
||||
int ret = 0;
|
||||
u64 last_committed = root->fs_info->last_trans_committed;
|
||||
|
||||
|
@ -3016,10 +3021,13 @@ int btrfs_log_inode_parent(struct btrfs_trans_handle *trans,
|
|||
if (IS_ROOT(parent))
|
||||
break;
|
||||
|
||||
parent = parent->d_parent;
|
||||
parent = dget_parent(parent);
|
||||
dput(old_parent);
|
||||
old_parent = parent;
|
||||
}
|
||||
ret = 0;
|
||||
end_trans:
|
||||
dput(old_parent);
|
||||
if (ret < 0) {
|
||||
BUG_ON(ret != -ENOSPC);
|
||||
root->fs_info->last_trans_log_full_commit = trans->transid;
|
||||
|
@ -3039,8 +3047,13 @@ end_no_trans:
|
|||
int btrfs_log_dentry_safe(struct btrfs_trans_handle *trans,
|
||||
struct btrfs_root *root, struct dentry *dentry)
|
||||
{
|
||||
return btrfs_log_inode_parent(trans, root, dentry->d_inode,
|
||||
dentry->d_parent, 0);
|
||||
struct dentry *parent = dget_parent(dentry);
|
||||
int ret;
|
||||
|
||||
ret = btrfs_log_inode_parent(trans, root, dentry->d_inode, parent, 0);
|
||||
dput(parent);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
Загрузка…
Ссылка в новой задаче