* Boston, MA 021110-1307, USA.
*/
-#include <linux/module.h>
#include <linux/buffer_head.h>
#include <linux/fs.h>
#include <linux/pagemap.h>
#include <linux/statfs.h>
#include <linux/compat.h>
#include <linux/bit_spinlock.h>
+#include <linux/version.h>
#include "ctree.h"
#include "disk-io.h"
#include "transaction.h"
static struct inode_operations btrfs_dir_inode_operations;
static struct inode_operations btrfs_symlink_inode_operations;
static struct inode_operations btrfs_dir_ro_inode_operations;
+static struct inode_operations btrfs_special_inode_operations;
static struct inode_operations btrfs_file_inode_operations;
static struct address_space_operations btrfs_aops;
static struct address_space_operations btrfs_symlink_aops;
struct btrfs_root *root = BTRFS_I(inode)->root;
struct btrfs_key location;
u64 alloc_group_block;
+ u32 rdev;
int ret;
path = btrfs_alloc_path();
inode->i_ctime.tv_nsec = btrfs_timespec_nsec(&inode_item->ctime);
inode->i_blocks = btrfs_inode_nblocks(inode_item);
inode->i_generation = btrfs_inode_generation(inode_item);
+ inode->i_rdev = 0;
+ rdev = btrfs_inode_rdev(inode_item);
alloc_group_block = btrfs_inode_block_group(inode_item);
BTRFS_I(inode)->block_group = btrfs_lookup_block_group(root->fs_info,
alloc_group_block);
mutex_unlock(&root->fs_info->fs_mutex);
switch (inode->i_mode & S_IFMT) {
-#if 0
- default:
- init_special_inode(inode, inode->i_mode,
- btrfs_inode_rdev(inode_item));
- break;
-#endif
case S_IFREG:
inode->i_mapping->a_ops = &btrfs_aops;
inode->i_fop = &btrfs_file_operations;
inode->i_op = &btrfs_symlink_inode_operations;
inode->i_mapping->a_ops = &btrfs_symlink_aops;
break;
+ default:
+ init_special_inode(inode, inode->i_mode, rdev);
+ break;
}
return;
btrfs_set_timespec_nsec(&item->ctime, inode->i_ctime.tv_nsec);
btrfs_set_inode_nblocks(item, inode->i_blocks);
btrfs_set_inode_generation(item, inode->i_generation);
+ btrfs_set_inode_rdev(item, inode->i_rdev);
btrfs_set_inode_block_group(item,
BTRFS_I(inode)->block_group->key.objectid);
}
btrfs_free_path(path);
if (!ret) {
dir->i_size -= name_len * 2;
+ dir->i_mtime = dir->i_ctime = CURRENT_TIME;
btrfs_update_inode(trans, root, dir);
drop_nlink(dentry->d_inode);
ret = btrfs_update_inode(trans, root, dentry->d_inode);
return ret;
}
-/*
- * truncates go from a high offset to a low offset. So, walk
- * from hi to lo in the node and issue readas. Stop when you find
- * keys from a different objectid
- */
-static void reada_truncate(struct btrfs_root *root, struct btrfs_path *path,
- u64 objectid)
-{
- struct btrfs_node *node;
- int i;
- int nritems;
- u64 item_objectid;
- u64 blocknr;
- int slot;
- int ret;
-
- if (!path->nodes[1])
- return;
- node = btrfs_buffer_node(path->nodes[1]);
- slot = path->slots[1];
- if (slot == 0)
- return;
- nritems = btrfs_header_nritems(&node->header);
- for (i = slot - 1; i >= 0; i--) {
- item_objectid = btrfs_disk_key_objectid(&node->ptrs[i].key);
- if (item_objectid != objectid)
- break;
- blocknr = btrfs_node_blockptr(node, i);
- ret = readahead_tree_block(root, blocknr);
- if (ret)
- break;
- }
-}
-
/*
* this can truncate away extent items, csum items and directory items.
* It starts at a high offset and removes keys until it can't find
int del_item;
path = btrfs_alloc_path();
+ path->reada = -1;
BUG_ON(!path);
/* FIXME, add redo link to tree so we don't leak on crash */
key.objectid = inode->i_ino;
BUG_ON(path->slots[0] == 0);
path->slots[0]--;
}
- reada_truncate(root, path, inode->i_ino);
leaf = btrfs_buffer_leaf(path->nodes[0]);
found_key = &leaf->items[path->slots[0]].key;
found_type = btrfs_disk_key_type(found_key);
extent_num_blocks);
inode->i_blocks -= (orig_num_blocks -
extent_num_blocks) << 3;
- mark_buffer_dirty(path->nodes[0]);
+ btrfs_mark_buffer_dirty(path->nodes[0]);
} else {
extent_start =
btrfs_file_extent_disk_blocknr(fi);
&alloc_hint);
if (ret)
goto out;
- ret = btrfs_alloc_extent(trans, root, inode->i_ino, 1,
+ ret = btrfs_alloc_extent(trans, root, inode->i_ino, 1, 0,
alloc_hint, (u64)-1, &ins, 1);
if (ret)
goto out;
return d_splice_alias(inode, dentry);
}
-/*
- * readahead one full node of leaves as long as their keys include
- * the objectid supplied
- */
-static void reada_leaves(struct btrfs_root *root, struct btrfs_path *path,
- u64 objectid)
-{
- struct btrfs_node *node;
- int i;
- u32 nritems;
- u64 item_objectid;
- u64 blocknr;
- int slot;
- int ret;
-
- if (!path->nodes[1])
- return;
- node = btrfs_buffer_node(path->nodes[1]);
- slot = path->slots[1];
- nritems = btrfs_header_nritems(&node->header);
- for (i = slot + 1; i < nritems; i++) {
- item_objectid = btrfs_disk_key_objectid(&node->ptrs[i].key);
- if (item_objectid != objectid)
- break;
- blocknr = btrfs_node_blockptr(node, i);
- ret = readahead_tree_block(root, blocknr);
- if (ret)
- break;
- }
-}
static unsigned char btrfs_filetype_table[] = {
DT_UNKNOWN, DT_REG, DT_DIR, DT_CHR, DT_BLK, DT_FIFO, DT_SOCK, DT_LNK
};
btrfs_set_key_type(&key, key_type);
key.offset = filp->f_pos;
path = btrfs_alloc_path();
+ path->reada = 1;
ret = btrfs_search_slot(NULL, root, &key, path, 0, 0);
if (ret < 0)
goto err;
advance = 0;
- reada_leaves(root, path, inode->i_ino);
while(1) {
leaf = btrfs_buffer_leaf(path->nodes[0]);
nritems = btrfs_header_nritems(&leaf->header);
slot = path->slots[0];
if (advance || slot >= nritems) {
if (slot >= nritems -1) {
- reada_leaves(root, path, inode->i_ino);
ret = btrfs_next_leaf(root, path);
if (ret)
break;
int ret;
struct btrfs_key key;
struct btrfs_root *root = BTRFS_I(dentry->d_parent->d_inode)->root;
+ struct inode *parent_inode;
key.objectid = inode->i_ino;
key.flags = 0;
btrfs_set_key_type(&key, BTRFS_INODE_ITEM_KEY);
dentry->d_parent->d_inode->i_ino,
&key, btrfs_inode_type(inode));
if (ret == 0) {
- dentry->d_parent->d_inode->i_size += dentry->d_name.len * 2;
+ parent_inode = dentry->d_parent->d_inode;
+ parent_inode->i_size += dentry->d_name.len * 2;
+ parent_inode->i_mtime = parent_inode->i_ctime = CURRENT_TIME;
ret = btrfs_update_inode(trans, root,
dentry->d_parent->d_inode);
}
return err;
}
+static int btrfs_mknod(struct inode *dir, struct dentry *dentry,
+ int mode, dev_t rdev)
+{
+ struct btrfs_trans_handle *trans;
+ struct btrfs_root *root = BTRFS_I(dir)->root;
+ struct inode *inode;
+ int err;
+ int drop_inode = 0;
+ u64 objectid;
+
+ if (!new_valid_dev(rdev))
+ return -EINVAL;
+
+ mutex_lock(&root->fs_info->fs_mutex);
+ trans = btrfs_start_transaction(root, 1);
+ btrfs_set_trans_block_group(trans, dir);
+
+ err = btrfs_find_free_objectid(trans, root, dir->i_ino, &objectid);
+ if (err) {
+ err = -ENOSPC;
+ goto out_unlock;
+ }
+
+ inode = btrfs_new_inode(trans, root, objectid,
+ BTRFS_I(dir)->block_group, mode);
+ err = PTR_ERR(inode);
+ if (IS_ERR(inode))
+ goto out_unlock;
+
+ btrfs_set_trans_block_group(trans, inode);
+ err = btrfs_add_nondir(trans, dentry, inode);
+ if (err)
+ drop_inode = 1;
+ else {
+ inode->i_op = &btrfs_special_inode_operations;
+ init_special_inode(inode, inode->i_mode, rdev);
+ }
+ dir->i_sb->s_dirt = 1;
+ btrfs_update_inode_block_group(trans, inode);
+ btrfs_update_inode_block_group(trans, dir);
+out_unlock:
+ btrfs_end_transaction(trans, root);
+ mutex_unlock(&root->fs_info->fs_mutex);
+
+ if (drop_inode) {
+ inode_dec_link_count(inode);
+ iput(inode);
+ }
+ btrfs_btree_balance_dirty(root);
+ return err;
+}
+
static int btrfs_create(struct inode *dir, struct dentry *dentry,
int mode, struct nameidata *nd)
{
if (create & BTRFS_GET_BLOCK_CREATE) {
struct btrfs_key ins;
ret = btrfs_alloc_extent(trans, root, inode->i_ino,
- 1, alloc_hint, (u64)-1,
+ 1, 0, alloc_hint, (u64)-1,
&ins, 1);
if (ret) {
err = ret;
trans = btrfs_start_transaction(root, 1);
BUG_ON(!trans);
- subvol = btrfs_alloc_free_block(trans, root, 0);
+ subvol = btrfs_alloc_free_block(trans, root, 0, 0);
if (IS_ERR(subvol))
return PTR_ERR(subvol);
leaf = btrfs_buffer_leaf(subvol);
btrfs_set_header_owner(&leaf->header, root->root_key.objectid);
memcpy(leaf->header.fsid, root->fs_info->disk_super->fsid,
sizeof(leaf->header.fsid));
- mark_buffer_dirty(subvol);
+ btrfs_mark_buffer_dirty(subvol);
inode_item = &root_item.inode;
memset(inode_item, 0, sizeof(*inode_item));
btrfs_set_root_blocknr(&root_item, bh_blocknr(subvol));
btrfs_set_root_refs(&root_item, 1);
+ memset(&root_item.drop_progress, 0, sizeof(root_item.drop_progress));
+ root_item.drop_level = 0;
brelse(subvol);
subvol = NULL;
else
ret = create_snapshot(root, vol_args.name, namelen);
break;
+
+ case BTRFS_IOC_DEFRAG:
+ mutex_lock(&root->fs_info->fs_mutex);
+ btrfs_defrag_root(root, 0);
+ btrfs_defrag_root(root->fs_info->extent_root, 0);
+ mutex_unlock(&root->fs_info->fs_mutex);
+ ret = 0;
+ break;
default:
return -ENOTTY;
}
kmem_cache_destroy(btrfs_path_cachep);
}
+static struct kmem_cache *cache_create(const char *name, size_t size,
+ unsigned long extra_flags,
+ void (*ctor)(void *, struct kmem_cache *,
+ unsigned long))
+{
+ return kmem_cache_create(name, size, 0, (SLAB_RECLAIM_ACCOUNT |
+ SLAB_MEM_SPREAD | extra_flags), ctor
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,23)
+ ,NULL
+#endif
+ );
+}
+
int btrfs_init_cachep(void)
{
- btrfs_inode_cachep = kmem_cache_create("btrfs_inode_cache",
- sizeof(struct btrfs_inode),
- 0, (SLAB_RECLAIM_ACCOUNT|
- SLAB_MEM_SPREAD),
- init_once, NULL);
+ btrfs_inode_cachep = cache_create("btrfs_inode_cache",
+ sizeof(struct btrfs_inode),
+ 0, init_once);
if (!btrfs_inode_cachep)
goto fail;
- btrfs_trans_handle_cachep = kmem_cache_create("btrfs_trans_handle_cache",
+ btrfs_trans_handle_cachep = cache_create("btrfs_trans_handle_cache",
sizeof(struct btrfs_trans_handle),
- 0, (SLAB_RECLAIM_ACCOUNT|
- SLAB_MEM_SPREAD),
- NULL, NULL);
+ 0, NULL);
if (!btrfs_trans_handle_cachep)
goto fail;
- btrfs_transaction_cachep = kmem_cache_create("btrfs_transaction_cache",
+ btrfs_transaction_cachep = cache_create("btrfs_transaction_cache",
sizeof(struct btrfs_transaction),
- 0, (SLAB_RECLAIM_ACCOUNT|
- SLAB_MEM_SPREAD),
- NULL, NULL);
+ 0, NULL);
if (!btrfs_transaction_cachep)
goto fail;
- btrfs_path_cachep = kmem_cache_create("btrfs_path_cache",
- sizeof(struct btrfs_transaction),
- 0, (SLAB_RECLAIM_ACCOUNT|
- SLAB_MEM_SPREAD),
- NULL, NULL);
+ btrfs_path_cachep = cache_create("btrfs_path_cache",
+ sizeof(struct btrfs_transaction),
+ 0, NULL);
if (!btrfs_path_cachep)
goto fail;
- btrfs_bit_radix_cachep = kmem_cache_create("btrfs_radix",
- 256,
- 0, (SLAB_RECLAIM_ACCOUNT|
- SLAB_MEM_SPREAD |
- SLAB_DESTROY_BY_RCU),
- NULL, NULL);
+ btrfs_bit_radix_cachep = cache_create("btrfs_radix", 256,
+ SLAB_DESTROY_BY_RCU, NULL);
if (!btrfs_bit_radix_cachep)
goto fail;
return 0;
ptr = btrfs_file_extent_inline_start(ei);
btrfs_memcpy(root, path->nodes[0]->b_data,
ptr, symname, name_len);
- mark_buffer_dirty(path->nodes[0]);
+ btrfs_mark_buffer_dirty(path->nodes[0]);
btrfs_free_path(path);
inode->i_op = &btrfs_symlink_inode_operations;
inode->i_mapping->a_ops = &btrfs_symlink_aops;
.rename = btrfs_rename,
.symlink = btrfs_symlink,
.setattr = btrfs_setattr,
+ .mknod = btrfs_mknod,
};
static struct inode_operations btrfs_dir_ro_inode_operations = {
.setattr = btrfs_setattr,
};
+static struct inode_operations btrfs_special_inode_operations = {
+ .getattr = btrfs_getattr,
+ .setattr = btrfs_setattr,
+};
+
static struct inode_operations btrfs_symlink_inode_operations = {
.readlink = generic_readlink,
.follow_link = page_follow_link_light,