Commit aa3fc525 authored by Linus Torvalds's avatar Linus Torvalds

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.
  ...
parents 555bdaef 5a92bc88
...@@ -91,23 +91,10 @@ static inline int compressed_bio_size(struct btrfs_root *root, ...@@ -91,23 +91,10 @@ static inline int compressed_bio_size(struct btrfs_root *root,
static struct bio *compressed_bio_alloc(struct block_device *bdev, static struct bio *compressed_bio_alloc(struct block_device *bdev,
u64 first_byte, gfp_t gfp_flags) u64 first_byte, gfp_t gfp_flags)
{ {
struct bio *bio;
int nr_vecs; int nr_vecs;
nr_vecs = bio_get_nr_vecs(bdev); nr_vecs = bio_get_nr_vecs(bdev);
bio = bio_alloc(gfp_flags, nr_vecs); return btrfs_bio_alloc(bdev, first_byte >> 9, nr_vecs, gfp_flags);
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;
} }
static int check_compressed_csum(struct inode *inode, static int check_compressed_csum(struct inode *inode,
......
...@@ -808,9 +808,9 @@ struct btrfs_block_group_cache { ...@@ -808,9 +808,9 @@ struct btrfs_block_group_cache {
int extents_thresh; int extents_thresh;
int free_extents; int free_extents;
int total_bitmaps; int total_bitmaps;
int ro:1; unsigned int ro:1;
int dirty:1; unsigned int dirty:1;
int iref:1; unsigned int iref:1;
int disk_cache_state; int disk_cache_state;
......
...@@ -28,6 +28,7 @@ ...@@ -28,6 +28,7 @@
#include <linux/freezer.h> #include <linux/freezer.h>
#include <linux/crc32c.h> #include <linux/crc32c.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/migrate.h>
#include "compat.h" #include "compat.h"
#include "ctree.h" #include "ctree.h"
#include "disk-io.h" #include "disk-io.h"
...@@ -355,6 +356,8 @@ static int csum_dirty_buffer(struct btrfs_root *root, struct page *page) ...@@ -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, ret = btree_read_extent_buffer_pages(root, eb, start + PAGE_CACHE_SIZE,
btrfs_header_generation(eb)); btrfs_header_generation(eb));
BUG_ON(ret); BUG_ON(ret);
WARN_ON(!btrfs_header_flag(eb, BTRFS_HEADER_FLAG_WRITTEN));
found_start = btrfs_header_bytenr(eb); found_start = btrfs_header_bytenr(eb);
if (found_start != start) { if (found_start != start) {
WARN_ON(1); WARN_ON(1);
...@@ -693,6 +696,29 @@ static int btree_submit_bio_hook(struct inode *inode, int rw, struct bio *bio, ...@@ -693,6 +696,29 @@ static int btree_submit_bio_hook(struct inode *inode, int rw, struct bio *bio,
__btree_submit_bio_done); __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) static int btree_writepage(struct page *page, struct writeback_control *wbc)
{ {
struct extent_io_tree *tree; struct extent_io_tree *tree;
...@@ -707,8 +733,7 @@ static int btree_writepage(struct page *page, struct writeback_control *wbc) ...@@ -707,8 +733,7 @@ static int btree_writepage(struct page *page, struct writeback_control *wbc)
} }
redirty_page_for_writepage(wbc, page); redirty_page_for_writepage(wbc, page);
eb = btrfs_find_tree_block(root, page_offset(page), eb = btrfs_find_tree_block(root, page_offset(page), PAGE_CACHE_SIZE);
PAGE_CACHE_SIZE);
WARN_ON(!eb); WARN_ON(!eb);
was_dirty = test_and_set_bit(EXTENT_BUFFER_DIRTY, &eb->bflags); was_dirty = test_and_set_bit(EXTENT_BUFFER_DIRTY, &eb->bflags);
...@@ -799,6 +824,9 @@ static const struct address_space_operations btree_aops = { ...@@ -799,6 +824,9 @@ static const struct address_space_operations btree_aops = {
.releasepage = btree_releasepage, .releasepage = btree_releasepage,
.invalidatepage = btree_invalidatepage, .invalidatepage = btree_invalidatepage,
.sync_page = block_sync_page, .sync_page = block_sync_page,
#ifdef CONFIG_MIGRATION
.migratepage = btree_migratepage,
#endif
}; };
int readahead_tree_block(struct btrfs_root *root, u64 bytenr, u32 blocksize, 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, ...@@ -1538,10 +1566,8 @@ struct btrfs_root *open_ctree(struct super_block *sb,
GFP_NOFS); GFP_NOFS);
struct btrfs_root *csum_root = kzalloc(sizeof(struct btrfs_root), struct btrfs_root *csum_root = kzalloc(sizeof(struct btrfs_root),
GFP_NOFS); GFP_NOFS);
struct btrfs_root *tree_root = kzalloc(sizeof(struct btrfs_root), struct btrfs_root *tree_root = btrfs_sb(sb);
GFP_NOFS); struct btrfs_fs_info *fs_info = tree_root->fs_info;
struct btrfs_fs_info *fs_info = kzalloc(sizeof(*fs_info),
GFP_NOFS);
struct btrfs_root *chunk_root = kzalloc(sizeof(struct btrfs_root), struct btrfs_root *chunk_root = kzalloc(sizeof(struct btrfs_root),
GFP_NOFS); GFP_NOFS);
struct btrfs_root *dev_root = kzalloc(sizeof(struct btrfs_root), struct btrfs_root *dev_root = kzalloc(sizeof(struct btrfs_root),
......
...@@ -232,9 +232,85 @@ static struct dentry *btrfs_get_parent(struct dentry *child) ...@@ -232,9 +232,85 @@ static struct dentry *btrfs_get_parent(struct dentry *child)
return ERR_PTR(ret); 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 = { const struct export_operations btrfs_export_ops = {
.encode_fh = btrfs_encode_fh, .encode_fh = btrfs_encode_fh,
.fh_to_dentry = btrfs_fh_to_dentry, .fh_to_dentry = btrfs_fh_to_dentry,
.fh_to_parent = btrfs_fh_to_parent, .fh_to_parent = btrfs_fh_to_parent,
.get_parent = btrfs_get_parent, .get_parent = btrfs_get_parent,
.get_name = btrfs_get_name,
}; };
...@@ -3412,7 +3412,7 @@ static int reserve_metadata_bytes(struct btrfs_trans_handle *trans, ...@@ -3412,7 +3412,7 @@ static int reserve_metadata_bytes(struct btrfs_trans_handle *trans,
* our reservation. * our reservation.
*/ */
if (unused <= space_info->total_bytes) { if (unused <= space_info->total_bytes) {
unused -= space_info->total_bytes; unused = space_info->total_bytes - unused;
if (unused >= num_bytes) { if (unused >= num_bytes) {
if (!reserved) if (!reserved)
space_info->bytes_reserved += orig_bytes; space_info->bytes_reserved += orig_bytes;
......
...@@ -1828,9 +1828,9 @@ static void end_bio_extent_preparewrite(struct bio *bio, int err) ...@@ -1828,9 +1828,9 @@ static void end_bio_extent_preparewrite(struct bio *bio, int err)
bio_put(bio); bio_put(bio);
} }
static struct bio * struct bio *
extent_bio_alloc(struct block_device *bdev, u64 first_sector, int nr_vecs, btrfs_bio_alloc(struct block_device *bdev, u64 first_sector, int nr_vecs,
gfp_t gfp_flags) gfp_t gfp_flags)
{ {
struct bio *bio; struct bio *bio;
...@@ -1919,7 +1919,7 @@ static int submit_extent_page(int rw, struct extent_io_tree *tree, ...@@ -1919,7 +1919,7 @@ static int submit_extent_page(int rw, struct extent_io_tree *tree,
else else
nr = bio_get_nr_vecs(bdev); 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_add_page(bio, page, page_size, offset);
bio->bi_end_io = end_io_func; bio->bi_end_io = end_io_func;
...@@ -2901,21 +2901,53 @@ sector_t extent_bmap(struct address_space *mapping, sector_t iblock, ...@@ -2901,21 +2901,53 @@ sector_t extent_bmap(struct address_space *mapping, sector_t iblock,
int extent_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo, int extent_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo,
__u64 start, __u64 len, get_extent_t *get_extent) __u64 start, __u64 len, get_extent_t *get_extent)
{ {
int ret; int ret = 0;
u64 off = start; u64 off = start;
u64 max = start + len; u64 max = start + len;
u32 flags = 0; u32 flags = 0;
u32 found_type;
u64 last;
u64 disko = 0; u64 disko = 0;
struct btrfs_key found_key;
struct extent_map *em = NULL; struct extent_map *em = NULL;
struct extent_state *cached_state = NULL; struct extent_state *cached_state = NULL;
struct btrfs_path *path;
struct btrfs_file_extent_item *item;
int end = 0; int end = 0;
u64 em_start = 0, em_len = 0; u64 em_start = 0, em_len = 0;
unsigned long emflags; unsigned long emflags;
ret = 0; int hole = 0;
if (len == 0) if (len == 0)
return -EINVAL; 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, lock_extent_bits(&BTRFS_I(inode)->io_tree, start, start + len, 0,
&cached_state, GFP_NOFS); &cached_state, GFP_NOFS);
em = get_extent(inode, NULL, 0, off, max - off, 0); 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, ...@@ -2925,11 +2957,18 @@ int extent_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo,
ret = PTR_ERR(em); ret = PTR_ERR(em);
goto out; goto out;
} }
while (!end) { while (!end) {
hole = 0;
off = em->start + em->len; off = em->start + em->len;
if (off >= max) if (off >= max)
end = 1; end = 1;
if (em->block_start == EXTENT_MAP_HOLE) {
hole = 1;
goto next;
}
em_start = em->start; em_start = em->start;
em_len = em->len; em_len = em->len;
...@@ -2939,8 +2978,6 @@ int extent_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo, ...@@ -2939,8 +2978,6 @@ int extent_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo,
if (em->block_start == EXTENT_MAP_LAST_BYTE) { if (em->block_start == EXTENT_MAP_LAST_BYTE) {
end = 1; end = 1;
flags |= FIEMAP_EXTENT_LAST; flags |= FIEMAP_EXTENT_LAST;
} else if (em->block_start == EXTENT_MAP_HOLE) {
flags |= FIEMAP_EXTENT_UNWRITTEN;
} else if (em->block_start == EXTENT_MAP_INLINE) { } else if (em->block_start == EXTENT_MAP_INLINE) {
flags |= (FIEMAP_EXTENT_DATA_INLINE | flags |= (FIEMAP_EXTENT_DATA_INLINE |
FIEMAP_EXTENT_NOT_ALIGNED); FIEMAP_EXTENT_NOT_ALIGNED);
...@@ -2953,10 +2990,10 @@ int extent_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo, ...@@ -2953,10 +2990,10 @@ int extent_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo,
if (test_bit(EXTENT_FLAG_COMPRESSED, &em->flags)) if (test_bit(EXTENT_FLAG_COMPRESSED, &em->flags))
flags |= FIEMAP_EXTENT_ENCODED; flags |= FIEMAP_EXTENT_ENCODED;
next:
emflags = em->flags; emflags = em->flags;
free_extent_map(em); free_extent_map(em);
em = NULL; em = NULL;
if (!end) { if (!end) {
em = get_extent(inode, NULL, 0, off, max - off, 0); em = get_extent(inode, NULL, 0, off, max - off, 0);
if (!em) if (!em)
...@@ -2967,15 +3004,23 @@ int extent_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo, ...@@ -2967,15 +3004,23 @@ int extent_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo,
} }
emflags = em->flags; emflags = em->flags;
} }
if (test_bit(EXTENT_FLAG_VACANCY, &emflags)) { if (test_bit(EXTENT_FLAG_VACANCY, &emflags)) {
flags |= FIEMAP_EXTENT_LAST; flags |= FIEMAP_EXTENT_LAST;
end = 1; end = 1;
} }
ret = fiemap_fill_next_extent(fieinfo, em_start, disko, if (em_start == last) {
em_len, flags); flags |= FIEMAP_EXTENT_LAST;
if (ret) end = 1;
goto out_free; }
if (!hole) {
ret = fiemap_fill_next_extent(fieinfo, em_start, disko,
em_len, flags);
if (ret)
goto out_free;
}
} }
out_free: out_free:
free_extent_map(em); free_extent_map(em);
...@@ -3836,8 +3881,10 @@ int try_release_extent_buffer(struct extent_io_tree *tree, struct page *page) ...@@ -3836,8 +3881,10 @@ int try_release_extent_buffer(struct extent_io_tree *tree, struct page *page)
spin_lock(&tree->buffer_lock); spin_lock(&tree->buffer_lock);
eb = radix_tree_lookup(&tree->buffer, start >> PAGE_CACHE_SHIFT); eb = radix_tree_lookup(&tree->buffer, start >> PAGE_CACHE_SHIFT);
if (!eb) if (!eb) {
goto out; spin_unlock(&tree->buffer_lock);
return ret;
}
if (test_bit(EXTENT_BUFFER_DIRTY, &eb->bflags)) { if (test_bit(EXTENT_BUFFER_DIRTY, &eb->bflags)) {
ret = 0; ret = 0;
......
...@@ -310,4 +310,7 @@ int extent_clear_unlock_delalloc(struct inode *inode, ...@@ -310,4 +310,7 @@ int extent_clear_unlock_delalloc(struct inode *inode,
struct extent_io_tree *tree, struct extent_io_tree *tree,
u64 start, u64 end, struct page *locked_page, u64 start, u64 end, struct page *locked_page,
unsigned long op); unsigned long op);
struct bio *
btrfs_bio_alloc(struct block_device *bdev, u64 first_sector, int nr_vecs,
gfp_t gfp_flags);
#endif #endif
...@@ -1047,8 +1047,14 @@ static ssize_t btrfs_file_aio_write(struct kiocb *iocb, ...@@ -1047,8 +1047,14 @@ static ssize_t btrfs_file_aio_write(struct kiocb *iocb,
if ((file->f_flags & O_DSYNC) || IS_SYNC(inode)) { if ((file->f_flags & O_DSYNC) || IS_SYNC(inode)) {
trans = btrfs_start_transaction(root, 0); 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, ret = btrfs_log_dentry_safe(trans, root,
file->f_dentry); file->f_dentry);
mutex_unlock(&inode->i_mutex);
if (ret == 0) { if (ret == 0) {
ret = btrfs_sync_log(trans, root); ret = btrfs_sync_log(trans, root);
if (ret == 0) if (ret == 0)
...@@ -1067,6 +1073,7 @@ static ssize_t btrfs_file_aio_write(struct kiocb *iocb, ...@@ -1067,6 +1073,7 @@ static ssize_t btrfs_file_aio_write(struct kiocb *iocb,
(start_pos + num_written - 1) >> PAGE_CACHE_SHIFT); (start_pos + num_written - 1) >> PAGE_CACHE_SHIFT);
} }
} }
done:
current->backing_dev_info = NULL; current->backing_dev_info = NULL;
return num_written ? num_written : err; return num_written ? num_written : err;
} }
......
This diff is collapsed.
...@@ -233,7 +233,8 @@ static noinline int create_subvol(struct btrfs_root *root, ...@@ -233,7 +233,8 @@ static noinline int create_subvol(struct btrfs_root *root,
struct btrfs_inode_item *inode_item; struct btrfs_inode_item *inode_item;
struct extent_buffer *leaf; struct extent_buffer *leaf;
struct btrfs_root *new_root; 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 ret;
int err; int err;
u64 objectid; u64 objectid;
...@@ -242,8 +243,13 @@ static noinline int create_subvol(struct btrfs_root *root, ...@@ -242,8 +243,13 @@ static noinline int create_subvol(struct btrfs_root *root,
ret = btrfs_find_free_objectid(NULL, root->fs_info->tree_root, ret = btrfs_find_free_objectid(NULL, root->fs_info->tree_root,
0, &objectid); 0, &objectid);
if (ret) if (ret) {
dput(parent);
return ret; return ret;
}
dir = parent->d_inode;
/* /*
* 1 - inode item * 1 - inode item
* 2 - refs * 2 - refs
...@@ -251,8 +257,10 @@ static noinline int create_subvol(struct btrfs_root *root, ...@@ -251,8 +257,10 @@ static noinline int create_subvol(struct btrfs_root *root,
* 2 - dir items * 2 - dir items
*/ */
trans = btrfs_start_transaction(root, 6); trans = btrfs_start_transaction(root, 6);
if (IS_ERR(trans)) if (IS_ERR(trans)) {
dput(parent);
return PTR_ERR(trans); return PTR_ERR(trans);
}
leaf = btrfs_alloc_free_block(trans, root, root->leafsize, leaf = btrfs_alloc_free_block(trans, root, root->leafsize,
0, objectid, NULL, 0, 0, 0); 0, objectid, NULL, 0, 0, 0);
...@@ -339,6 +347,7 @@ static noinline int create_subvol(struct btrfs_root *root, ...@@ -339,6 +347,7 @@ static noinline int create_subvol(struct btrfs_root *root,
d_instantiate(dentry, btrfs_lookup_dentry(dir, dentry)); d_instantiate(dentry, btrfs_lookup_dentry(dir, dentry));
fail: fail:
dput(parent);
if (async_transid) { if (async_transid) {
*async_transid = trans->transid; *async_transid = trans->transid;
err = btrfs_commit_transaction_async(trans, root, 1); err = btrfs_commit_transaction_async(trans, root, 1);
...@@ -354,6 +363,7 @@ static int create_snapshot(struct btrfs_root *root, struct dentry *dentry, ...@@ -354,6 +363,7 @@ static int create_snapshot(struct btrfs_root *root, struct dentry *dentry,
char *name, int namelen, u64 *async_transid) char *name, int namelen, u64 *async_transid)
{ {
struct inode *inode; struct inode *inode;
struct dentry *parent;
struct btrfs_pending_snapshot *pending_snapshot; struct btrfs_pending_snapshot *pending_snapshot;
struct btrfs_trans_handle *trans; struct btrfs_trans_handle *trans;
int ret; int ret;
...@@ -396,7 +406,9 @@ static int create_snapshot(struct btrfs_root *root, struct dentry *dentry, ...@@ -396,7 +406,9 @@ static int create_snapshot(struct btrfs_root *root, struct dentry *dentry,
btrfs_orphan_cleanup(pending_snapshot->snap); 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)) { if (IS_ERR(inode)) {
ret = PTR_ERR(inode); ret = PTR_ERR(inode);
goto fail; goto fail;
...@@ -1669,12 +1681,11 @@ static noinline long btrfs_ioctl_clone(struct file *file, unsigned long srcfd, ...@@ -1669,12 +1681,11 @@ static noinline long btrfs_ioctl_clone(struct file *file, unsigned long srcfd,
olen = len = src->i_size - off; olen = len = src->i_size - off;
/* if we extend to eof, continue to block boundary */ /* if we extend to eof, continue to block boundary */
if (off + len == src->i_size) if (off + len == src->i_size)
len = ((src->i_size + bs-1) & ~(bs-1)) len = ALIGN(src->i_size, bs) - off;
- off;
/* verify the end result is block aligned */ /* verify the end result is block aligned */
if ((off & (bs-1)) || if (!IS_ALIGNED(off, bs) || !IS_ALIGNED(off + len, bs) ||
((off + len) & (bs-1))) !IS_ALIGNED(destoff, bs))
goto out_unlock; goto out_unlock;
/* do any pending delalloc/csum calc on src, one way or /* 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, ...@@ -1874,8 +1885,8 @@ static noinline long btrfs_ioctl_clone(struct file *file, unsigned long srcfd,
* but shouldn't round up the file size * but shouldn't round up the file size
*/ */
endoff = new_key.offset + datal; endoff = new_key.offset + datal;
if (endoff > off+olen) if (endoff > destoff+olen)
endoff = off+olen; endoff = destoff+olen;
if (endoff > inode->i_size) if (endoff > inode->i_size)
btrfs_i_size_write(inode, endoff); btrfs_i_size_write(inode, endoff);
......
...@@ -248,6 +248,73 @@ int btrfs_add_ordered_sum(struct inode *inode, ...@@ -248,6 +248,73 @@ int btrfs_add_ordered_sum(struct inode *inode,
return 0; 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 * this is used to account for finished IO across a given range
* of the file. The IO should not span ordered extents. If * of the file. The IO should not span ordered extents. If
......
...@@ -141,6 +141,9 @@ int btrfs_remove_ordered_extent(struct inode *inode, ...@@ -141,6 +141,9 @@ int btrfs_remove_ordered_extent(struct inode *inode,
int btrfs_dec_test_ordered_pending(struct inode *inode, int btrfs_dec_test_ordered_pending(struct inode *inode,
struct btrfs_ordered_extent **cached, struct btrfs_ordered_extent **cached,
u64 file_offset, u64 io_size); 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, int btrfs_add_ordered_extent(struct inode *inode, u64 file_offset,
u64 start, u64 len, u64 disk_len, int type); u64 start, u64 len, u64 disk_len, int type);
int btrfs_add_ordered_extent_dio(struct inode *inode, u64 file_offset, 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) ...@@ -244,6 +244,7 @@ int btrfs_parse_options(struct btrfs_root *root, char *options)
case Opt_space_cache: case Opt_space_cache:
printk(KERN_INFO "btrfs: enabling disk space caching\n"); printk(KERN_INFO "btrfs: enabling disk space caching\n");
btrfs_set_opt(info->mount_opt, SPACE_CACHE); btrfs_set_opt(info->mount_opt, SPACE_CACHE);
break;
case Opt_clear_cache: case Opt_clear_cache:
printk(KERN_INFO "btrfs: force clearing of disk cache\n"); printk(KERN_INFO "btrfs: force clearing of disk cache\n");
btrfs_set_opt(info->mount_opt, CLEAR_CACHE); btrfs_set_opt(info->mount_opt, CLEAR_CACHE);
...@@ -562,12 +563,26 @@ static int btrfs_show_options(struct seq_file *seq, struct vfsmount *vfs) ...@@ -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) 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); 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. * 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, ...@@ -581,6 +596,8 @@ static struct dentry *btrfs_mount(struct file_system_type *fs_type, int flags,
struct super_block *s; struct super_block *s;
struct dentry *root; struct dentry *root;
struct btrfs_fs_devices *fs_devices = NULL; 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; fmode_t mode = FMODE_READ;
char *subvol_name = NULL; char *subvol_name = NULL;
u64 subvol_objectid = 0; u64 subvol_objectid = 0;
...@@ -608,8 +625,24 @@ static struct dentry *btrfs_mount(struct file_system_type *fs_type, int flags, ...@@ -608,8 +625,24 @@ static struct dentry *btrfs_mount(struct file_system_type *fs_type, int flags,
goto error_close_devices; 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; 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)) if (IS_ERR(s))
goto error_s; goto error_s;
...@@ -675,6 +708,8 @@ static struct dentry *btrfs_mount(struct file_system_type *fs_type, int flags, ...@@ -675,6 +708,8 @@ static struct dentry *btrfs_mount(struct file_system_type *fs_type, int flags,
error = PTR_ERR(s); error = PTR_ERR(s);
error_close_devices: error_close_devices:
btrfs_close_devices(fs_devices); btrfs_close_devices(fs_devices);
kfree(fs_info);
kfree(tree_root);
error_free_subvol_name: error_free_subvol_name:
kfree(subvol_name); kfree(subvol_name);
return ERR_PTR(error); return ERR_PTR(error);
......
...@@ -902,6 +902,7 @@ static noinline int create_pending_snapshot(struct btrfs_trans_handle *trans, ...@@ -902,6 +902,7 @@ static noinline int create_pending_snapshot(struct btrfs_trans_handle *trans,
struct btrfs_root *root = pending->root; struct btrfs_root *root = pending->root;
struct btrfs_root *parent_root; struct btrfs_root *parent_root;
struct inode *parent_inode; struct inode *parent_inode;
struct dentry *parent;
struct dentry *dentry; struct dentry *dentry;
struct extent_buffer *tmp; struct extent_buffer *tmp;
struct extent_buffer *old; struct extent_buffer *old;
...@@ -941,7 +942,8 @@ static noinline int create_pending_snapshot(struct btrfs_trans_handle *trans, ...@@ -941,7 +942,8 @@ static noinline int create_pending_snapshot(struct btrfs_trans_handle *trans,
trans->block_rsv = &pending->block_rsv; trans->block_rsv = &pending->block_rsv;
dentry = pending->dentry; 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; parent_root = BTRFS_I(parent_inode)->root;
record_root_in_trans(trans, parent_root); record_root_in_trans(trans, parent_root);
...@@ -989,6 +991,7 @@ static noinline int create_pending_snapshot(struct btrfs_trans_handle *trans, ...@@ -989,6 +991,7 @@ static noinline int create_pending_snapshot(struct btrfs_trans_handle *trans,
parent_inode->i_ino, index, parent_inode->i_ino, index,
dentry->d_name.name, dentry->d_name.len); dentry->d_name.name, dentry->d_name.len);
BUG_ON(ret); BUG_ON(ret);
dput(parent);
key.offset = (u64)-1; key.offset = (u64)-1;
pending->snap = btrfs_read_fs_root_no_name(root->fs_info, &key); 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, ...@@ -2869,6 +2869,7 @@ static noinline int check_parent_dirs_for_sync(struct btrfs_trans_handle *trans,
{ {
int ret = 0; int ret = 0;
struct btrfs_root *root; struct btrfs_root *root;
struct dentry *old_parent = NULL;
/* /*
* for regular files, if its inode is already on disk, we don't * 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, ...@@ -2910,10 +2911,13 @@ static noinline int check_parent_dirs_for_sync(struct btrfs_trans_handle *trans,
if (IS_ROOT(parent)) if (IS_ROOT(parent))
break; break;
parent = parent->d_parent; parent = dget_parent(parent);
dput(old_parent);
old_parent = parent;
inode = parent->d_inode; inode = parent->d_inode;
} }
dput(old_parent);
out: out:
return ret; return ret;
} }
...@@ -2945,6 +2949,7 @@ int btrfs_log_inode_parent(struct btrfs_trans_handle *trans, ...@@ -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; int inode_only = exists_only ? LOG_INODE_EXISTS : LOG_INODE_ALL;
struct super_block *sb; struct super_block *sb;
struct dentry *old_parent = NULL;
int ret = 0; int ret = 0;
u64 last_committed = root->fs_info->last_trans_committed; u64 last_committed = root->fs_info->last_trans_committed;
...@@ -3016,10 +3021,13 @@ int btrfs_log_inode_parent(struct btrfs_trans_handle *trans, ...@@ -3016,10 +3021,13 @@ int btrfs_log_inode_parent(struct btrfs_trans_handle *trans,
if (IS_ROOT(parent)) if (IS_ROOT(parent))
break; break;
parent = parent->d_parent; parent = dget_parent(parent);
dput(old_parent);
old_parent = parent;
} }
ret = 0; ret = 0;
end_trans: end_trans:
dput(old_parent);
if (ret < 0) { if (ret < 0) {
BUG_ON(ret != -ENOSPC); BUG_ON(ret != -ENOSPC);
root->fs_info->last_trans_log_full_commit = trans->transid; root->fs_info->last_trans_log_full_commit = trans->transid;
...@@ -3039,8 +3047,13 @@ int btrfs_log_inode_parent(struct btrfs_trans_handle *trans, ...@@ -3039,8 +3047,13 @@ int btrfs_log_inode_parent(struct btrfs_trans_handle *trans,
int btrfs_log_dentry_safe(struct btrfs_trans_handle *trans, int btrfs_log_dentry_safe(struct btrfs_trans_handle *trans,
struct btrfs_root *root, struct dentry *dentry) struct btrfs_root *root, struct dentry *dentry)
{ {
return btrfs_log_inode_parent(trans, root, dentry->d_inode, struct dentry *parent = dget_parent(dentry);
dentry->d_parent, 0); int ret;
ret = btrfs_log_inode_parent(trans, root, dentry->d_inode, parent, 0);
dput(parent);
return ret;
} }
/* /*
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment