@@ -2106,6 +2106,11 @@ struct btrfs_ioctl_defrag_range_args {
#define BTRFS_DEV_REPLACE_KEY 250
/*
+ * Used to record deleted xattrs in a log tree.
+ */
+#define BTRFS_DELETED_XATTR_ITEM_KEY 254
+
+/*
* Stores items that allow to quickly map UUIDs to something else.
* These items are part of the filesystem UUID tree.
* The key is built like this:
@@ -3770,11 +3775,21 @@ int btrfs_insert_xattr_item(struct btrfs_trans_handle *trans,
struct btrfs_path *path, u64 objectid,
const char *name, u16 name_len,
const void *data, u16 data_len);
+int btrfs_insert_deleted_xattr_item(struct btrfs_trans_handle *trans,
+ struct btrfs_root *root,
+ struct btrfs_path *path, u64 objectid,
+ const char *name, u16 name_len);
struct btrfs_dir_item *btrfs_lookup_xattr(struct btrfs_trans_handle *trans,
struct btrfs_root *root,
struct btrfs_path *path, u64 dir,
const char *name, u16 name_len,
int mod);
+struct btrfs_dir_item *
+btrfs_lookup_deleted_xattr(struct btrfs_trans_handle *trans,
+ struct btrfs_root *root,
+ struct btrfs_path *path, u64 dir,
+ const char *name, u16 name_len,
+ int mod);
int verify_dir_item(struct btrfs_root *root,
struct extent_buffer *leaf,
struct btrfs_dir_item *dir_item);
@@ -65,11 +65,12 @@ static struct btrfs_dir_item *insert_with_overflow(struct btrfs_trans_handle
* xattrs work a lot like directories, this inserts an xattr item
* into the tree
*/
-int btrfs_insert_xattr_item(struct btrfs_trans_handle *trans,
- struct btrfs_root *root,
- struct btrfs_path *path, u64 objectid,
- const char *name, u16 name_len,
- const void *data, u16 data_len)
+static int do_btrfs_insert_xattr_item(struct btrfs_trans_handle *trans,
+ struct btrfs_root *root,
+ u8 key_type,
+ struct btrfs_path *path, u64 objectid,
+ const char *name, u16 name_len,
+ const void *data, u16 data_len)
{
int ret = 0;
struct btrfs_dir_item *dir_item;
@@ -82,7 +83,7 @@ int btrfs_insert_xattr_item(struct btrfs_trans_handle *trans,
BUG_ON(name_len + data_len > BTRFS_MAX_XATTR_SIZE(root));
key.objectid = objectid;
- key.type = BTRFS_XATTR_ITEM_KEY;
+ key.type = key_type;
key.offset = btrfs_name_hash(name, name_len);
data_size = sizeof(*dir_item) + name_len + data_len;
@@ -109,6 +110,29 @@ int btrfs_insert_xattr_item(struct btrfs_trans_handle *trans,
return ret;
}
+int btrfs_insert_xattr_item(struct btrfs_trans_handle *trans,
+ struct btrfs_root *root,
+ struct btrfs_path *path, u64 objectid,
+ const char *name, u16 name_len,
+ const void *data, u16 data_len)
+{
+ return do_btrfs_insert_xattr_item(trans, root, BTRFS_XATTR_ITEM_KEY,
+ path, objectid, name, name_len,
+ data, data_len);
+}
+
+int btrfs_insert_deleted_xattr_item(struct btrfs_trans_handle *trans,
+ struct btrfs_root *root,
+ struct btrfs_path *path, u64 objectid,
+ const char *name, u16 name_len)
+{
+ return do_btrfs_insert_xattr_item(trans, root,
+ BTRFS_DELETED_XATTR_ITEM_KEY,
+ path, objectid, name, name_len,
+ "", 0);
+}
+
+
/*
* insert a directory item in the tree, doing all the magic for
* both indexes. 'dir' indicates which objectid to insert it into,
@@ -351,11 +375,13 @@ btrfs_search_dir_index_item(struct btrfs_root *root,
return NULL;
}
-struct btrfs_dir_item *btrfs_lookup_xattr(struct btrfs_trans_handle *trans,
- struct btrfs_root *root,
- struct btrfs_path *path, u64 dir,
- const char *name, u16 name_len,
- int mod)
+static struct btrfs_dir_item *
+do_btrfs_lookup_xattr(struct btrfs_trans_handle *trans,
+ struct btrfs_root *root,
+ u8 key_type,
+ struct btrfs_path *path, u64 dir,
+ const char *name, u16 name_len,
+ int mod)
{
int ret;
struct btrfs_key key;
@@ -363,7 +389,7 @@ struct btrfs_dir_item *btrfs_lookup_xattr(struct btrfs_trans_handle *trans,
int cow = mod != 0;
key.objectid = dir;
- key.type = BTRFS_XATTR_ITEM_KEY;
+ key.type = key_type;
key.offset = btrfs_name_hash(name, name_len);
ret = btrfs_search_slot(trans, root, &key, path, ins_len, cow);
if (ret < 0)
@@ -374,6 +400,27 @@ struct btrfs_dir_item *btrfs_lookup_xattr(struct btrfs_trans_handle *trans,
return btrfs_match_dir_item_name(root, path, name, name_len);
}
+struct btrfs_dir_item *btrfs_lookup_xattr(struct btrfs_trans_handle *trans,
+ struct btrfs_root *root,
+ struct btrfs_path *path, u64 dir,
+ const char *name, u16 name_len,
+ int mod)
+{
+ return do_btrfs_lookup_xattr(trans, root, BTRFS_XATTR_ITEM_KEY, path,
+ dir, name, name_len, mod);
+}
+
+struct btrfs_dir_item *
+btrfs_lookup_deleted_xattr(struct btrfs_trans_handle *trans,
+ struct btrfs_root *root,
+ struct btrfs_path *path, u64 dir,
+ const char *name, u16 name_len,
+ int mod)
+{
+ return do_btrfs_lookup_xattr(trans, root, BTRFS_DELETED_XATTR_ITEM_KEY,
+ path, dir, name, name_len, mod);
+}
+
/*
* helper function to look at the directory item pointed to by 'path'
* this walks through all the entries in a dir item and finds one
@@ -4260,7 +4260,10 @@ int btrfs_truncate_inode_items(struct btrfs_trans_handle *trans,
key.objectid = ino;
key.offset = (u64)-1;
- key.type = (u8)-1;
+ if (root->root_key.objectid == BTRFS_TREE_LOG_OBJECTID)
+ key.type = BTRFS_DELETED_XATTR_ITEM_KEY - 1;
+ else
+ key.type = (u8)-1;
search_again:
/*
@@ -1976,34 +1976,35 @@ static int replay_xattr_deletes(struct btrfs_trans_handle *trans,
return -ENOMEM;
search_key.objectid = ino;
- search_key.type = BTRFS_XATTR_ITEM_KEY;
+ search_key.type = BTRFS_DELETED_XATTR_ITEM_KEY;
search_key.offset = 0;
-again:
- ret = btrfs_search_slot(NULL, root, &search_key, path, 0, 0);
+ ret = btrfs_search_slot(NULL, log, &search_key, log_path, 0, 0);
if (ret < 0)
goto out;
process_leaf:
- nritems = btrfs_header_nritems(path->nodes[0]);
- for (i = path->slots[0]; i < nritems; i++) {
+ nritems = btrfs_header_nritems(log_path->nodes[0]);
+ for (i = log_path->slots[0]; i < nritems; i++) {
+ struct extent_buffer *leaf = log_path->nodes[0];
struct btrfs_key key;
struct btrfs_dir_item *di;
struct btrfs_dir_item *log_di;
u32 total_size;
u32 cur;
- btrfs_item_key_to_cpu(path->nodes[0], &key, i);
- if (key.objectid != ino || key.type != BTRFS_XATTR_ITEM_KEY) {
+ btrfs_item_key_to_cpu(leaf, &key, i);
+ if (key.objectid != ino ||
+ key.type != BTRFS_DELETED_XATTR_ITEM_KEY) {
ret = 0;
goto out;
}
- di = btrfs_item_ptr(path->nodes[0], i, struct btrfs_dir_item);
- total_size = btrfs_item_size_nr(path->nodes[0], i);
+ log_di = btrfs_item_ptr(leaf, i, struct btrfs_dir_item);
+ total_size = btrfs_item_size_nr(leaf, i);
cur = 0;
while (cur < total_size) {
- u16 name_len = btrfs_dir_name_len(path->nodes[0], di);
- u16 data_len = btrfs_dir_data_len(path->nodes[0], di);
- u32 this_len = sizeof(*di) + name_len + data_len;
+ u16 name_len = btrfs_dir_name_len(leaf, log_di);
+ u16 data_len = btrfs_dir_data_len(leaf, log_di);
+ u32 this_len = sizeof(*log_di) + name_len + data_len;
char *name;
name = kmalloc(name_len, GFP_NOFS);
@@ -2011,41 +2012,29 @@ process_leaf:
ret = -ENOMEM;
goto out;
}
- read_extent_buffer(path->nodes[0], name,
- (unsigned long)(di + 1), name_len);
+ read_extent_buffer(leaf, name,
+ (unsigned long)(log_di + 1),
+ name_len);
- log_di = btrfs_lookup_xattr(NULL, log, log_path, ino,
- name, name_len, 0);
- btrfs_release_path(log_path);
- if (!log_di) {
- /* Doesn't exist in log tree, so delete it. */
- btrfs_release_path(path);
- di = btrfs_lookup_xattr(trans, root, path, ino,
- name, name_len, -1);
- kfree(name);
- if (IS_ERR(di)) {
- ret = PTR_ERR(di);
- goto out;
- }
- ASSERT(di);
+ di = btrfs_lookup_xattr(trans, root, path, ino,
+ name, name_len, -1);
+ kfree(name);
+ if (IS_ERR(di)) {
+ ret = PTR_ERR(di);
+ goto out;
+ } else if (di) {
ret = btrfs_delete_one_dir_name(trans, root,
path, di);
if (ret)
goto out;
- btrfs_release_path(path);
- search_key = key;
- goto again;
- }
- kfree(name);
- if (IS_ERR(log_di)) {
- ret = PTR_ERR(log_di);
- goto out;
}
+ btrfs_release_path(path);
cur += this_len;
- di = (struct btrfs_dir_item *)((char *)di + this_len);
+ log_di = (struct btrfs_dir_item *)((char *)log_di +
+ this_len);
}
}
- ret = btrfs_next_leaf(root, path);
+ ret = btrfs_next_leaf(log, log_path);
if (ret > 0)
ret = 0;
else if (ret == 0)
@@ -2254,6 +2243,9 @@ static int replay_one_buffer(struct btrfs_root *log, struct extent_buffer *eb,
if (wc->stage < LOG_WALK_REPLAY_ALL)
continue;
+ if (key.type == BTRFS_DELETED_XATTR_ITEM_KEY)
+ continue;
+
/* these keys are simply copied */
if (key.type == BTRFS_XATTR_ITEM_KEY) {
ret = overwrite_item(wc->trans, root, path,
@@ -3090,6 +3082,76 @@ int btrfs_del_inode_ref_in_log(struct btrfs_trans_handle *trans,
return ret;
}
+int btrfs_record_deleted_xattr_in_log(struct btrfs_trans_handle *trans,
+ struct btrfs_root *root,
+ struct btrfs_path *path,
+ struct inode *inode,
+ const char *name, int name_len)
+{
+ struct btrfs_root *log;
+ struct btrfs_log_ctx ctx;
+ int ret;
+
+ if (btrfs_test_opt(root, NOTREELOG))
+ return 0;
+
+ btrfs_init_log_ctx(&ctx);
+ ret = start_log_trans(trans, root, &ctx);
+ if (ret)
+ return ret;
+
+ log = root->log_root;
+ mutex_lock(&BTRFS_I(inode)->log_mutex);
+ ret = btrfs_insert_deleted_xattr_item(trans, log, path,
+ btrfs_ino(inode),
+ name, name_len);
+ mutex_unlock(&BTRFS_I(inode)->log_mutex);
+ if (ret == -ENOSPC || ret == -EOVERFLOW) {
+ btrfs_set_log_full_commit(root->fs_info, trans);
+ ret = 0;
+ }
+
+ btrfs_remove_log_ctx(root, &ctx);
+ btrfs_end_log_trans(root);
+
+ return ret;
+}
+
+int btrfs_del_deleted_xattr_in_log(struct btrfs_trans_handle *trans,
+ struct btrfs_root *root,
+ struct btrfs_path *path,
+ struct inode *inode,
+ const char *name, int name_len)
+{
+ struct btrfs_root *log;
+ struct btrfs_dir_item *di;
+ int ret;
+
+ if (BTRFS_I(inode)->logged_trans < trans->transid)
+ return 0;
+
+ ret = join_running_log_trans(root);
+ if (ret)
+ return 0;
+
+ log = root->log_root;
+ ret = 0;
+ mutex_lock(&BTRFS_I(inode)->log_mutex);
+ di = btrfs_lookup_deleted_xattr(trans, log, path, btrfs_ino(inode),
+ name, name_len, -1);
+ if (di)
+ ret = btrfs_delete_one_dir_name(trans, log, path, di);
+ mutex_unlock(&BTRFS_I(inode)->log_mutex);
+ if (ret == -ENOSPC) {
+ btrfs_set_log_full_commit(root->fs_info, trans);
+ ret = 0;
+ }
+
+ btrfs_end_log_trans(root);
+
+ return ret;
+}
+
/*
* creates a range item in the log for 'dirid'. first_offset and
* last_offset tell us which parts of the key space the log should
@@ -74,6 +74,16 @@ int btrfs_del_inode_ref_in_log(struct btrfs_trans_handle *trans,
struct btrfs_root *root,
const char *name, int name_len,
struct inode *inode, u64 dirid);
+int btrfs_record_deleted_xattr_in_log(struct btrfs_trans_handle *trans,
+ struct btrfs_root *root,
+ struct btrfs_path *path,
+ struct inode *inode,
+ const char *name, int name_len);
+int btrfs_del_deleted_xattr_in_log(struct btrfs_trans_handle *trans,
+ struct btrfs_root *root,
+ struct btrfs_path *path,
+ struct inode *inode,
+ const char *name, int name_len);
void btrfs_end_log_trans(struct btrfs_root *root);
int btrfs_pin_log_trans(struct btrfs_root *root);
void btrfs_record_unlink_dir(struct btrfs_trans_handle *trans,
@@ -30,6 +30,7 @@
#include "disk-io.h"
#include "props.h"
#include "locking.h"
+#include "tree-log.h"
ssize_t __btrfs_getxattr(struct inode *inode, const char *name,
@@ -115,6 +116,11 @@ static int do_setxattr(struct btrfs_trans_handle *trans,
ret = PTR_ERR(di);
else if (di)
ret = btrfs_delete_one_dir_name(trans, root, path, di);
+ if (ret || !di)
+ goto out;
+ btrfs_release_path(path);
+ ret = btrfs_record_deleted_xattr_in_log(trans, root, path,
+ inode, name, name_len);
goto out;
}
@@ -222,6 +228,10 @@ static int do_setxattr(struct btrfs_trans_handle *trans,
* filled it.
*/
}
+
+ btrfs_release_path(path);
+ ret = btrfs_del_deleted_xattr_in_log(trans, root, path, inode,
+ name, name_len);
out:
btrfs_free_path(path);
return ret;