btrfs: remove location key from struct btrfs_inode

Currently struct btrfs_inode has a key member, named "location", that is
either:

1) The key of the inode's item. In this case the objectid is the number
   of the inode;

2) A key stored in a dir entry with a type of BTRFS_ROOT_ITEM_KEY, for
   the case where we have a root that is a snapshot of a subvolume that
   points to other subvolumes. In this case the objectid is the ID of
   a subvolume inside the snapshotted parent subvolume.

The key is only used to lookup the inode item for the first case, while
for the second it's never used since it corresponds to directory stubs
created with new_simple_dir() and which are marked as dummy, so there's
no actual inode item to ever update. In the second case we only check
the key type at btrfs_ino() for 32 bits platforms and its objectid is
only needed for unlink.

Instead of using a key we can do fine with just the objectid, since we
can generate the key whenever we need it having only the objectid, as
in all use cases the type is always BTRFS_INODE_ITEM_KEY and the offset
is always 0.

So use only an objectid instead of a full key. This reduces the size of
struct btrfs_inode from 1048 bytes down to 1040 bytes on a release kernel.

Signed-off-by: Filipe Manana <fdmanana@suse.com>
Reviewed-by: David Sterba <dsterba@suse.com>
Signed-off-by: David Sterba <dsterba@suse.com>
This commit is contained in:
Filipe Manana 2024-05-03 18:10:06 +01:00 committed by David Sterba
parent 3d7db6e8bd
commit 068fc8f914
7 changed files with 63 additions and 33 deletions

View File

@ -99,6 +99,29 @@ enum {
* range). * range).
*/ */
BTRFS_INODE_COW_WRITE_ERROR, BTRFS_INODE_COW_WRITE_ERROR,
/*
* Indicate this is a directory that points to a subvolume for which
* there is no root reference item. That's a case like the following:
*
* $ btrfs subvolume create /mnt/parent
* $ btrfs subvolume create /mnt/parent/child
* $ btrfs subvolume snapshot /mnt/parent /mnt/snap
*
* If subvolume "parent" is root 256, subvolume "child" is root 257 and
* snapshot "snap" is root 258, then there's no root reference item (key
* BTRFS_ROOT_REF_KEY in the root tree) for the subvolume "child"
* associated to root 258 (the snapshot) - there's only for the root
* of the "parent" subvolume (root 256). In the chunk root we have a
* (256 BTRFS_ROOT_REF_KEY 257) key but we don't have a
* (258 BTRFS_ROOT_REF_KEY 257) key - the sames goes for backrefs, we
* have a (257 BTRFS_ROOT_BACKREF_KEY 256) but we don't have a
* (257 BTRFS_ROOT_BACKREF_KEY 258) key.
*
* So when opening the "child" dentry from the snapshot's directory,
* we don't find a root ref item and we create a stub inode. This is
* done at new_simple_dir(), called from btrfs_lookup_dentry().
*/
BTRFS_INODE_ROOT_STUB,
}; };
/* in memory btrfs inode */ /* in memory btrfs inode */
@ -106,10 +129,15 @@ struct btrfs_inode {
/* which subvolume this inode belongs to */ /* which subvolume this inode belongs to */
struct btrfs_root *root; struct btrfs_root *root;
/* key used to find this inode on disk. This is used by the code /*
* to read in roots of subvolumes * This is either:
*
* 1) The objectid of the corresponding BTRFS_INODE_ITEM_KEY;
*
* 2) In case this a root stub inode (BTRFS_INODE_ROOT_STUB flag set),
* the ID of that root.
*/ */
struct btrfs_key location; u64 objectid;
/* Cached value of inode property 'compression'. */ /* Cached value of inode property 'compression'. */
u8 prop_compress; u8 prop_compress;
@ -340,10 +368,9 @@ static inline unsigned long btrfs_inode_hash(u64 objectid,
*/ */
static inline u64 btrfs_ino(const struct btrfs_inode *inode) static inline u64 btrfs_ino(const struct btrfs_inode *inode)
{ {
u64 ino = inode->location.objectid; u64 ino = inode->objectid;
/* type == BTRFS_ROOT_ITEM_KEY: subvol dir */ if (test_bit(BTRFS_INODE_ROOT_STUB, &inode->runtime_flags))
if (inode->location.type == BTRFS_ROOT_ITEM_KEY)
ino = inode->vfs_inode.i_ino; ino = inode->vfs_inode.i_ino;
return ino; return ino;
} }
@ -357,6 +384,14 @@ static inline u64 btrfs_ino(const struct btrfs_inode *inode)
#endif #endif
static inline void btrfs_get_inode_key(const struct btrfs_inode *inode,
struct btrfs_key *key)
{
key->objectid = inode->objectid;
key->type = BTRFS_INODE_ITEM_KEY;
key->offset = 0;
}
static inline void btrfs_i_size_write(struct btrfs_inode *inode, u64 size) static inline void btrfs_i_size_write(struct btrfs_inode *inode, u64 size)
{ {
i_size_write(&inode->vfs_inode, size); i_size_write(&inode->vfs_inode, size);

View File

@ -1944,9 +1944,7 @@ static int btrfs_init_btree_inode(struct super_block *sb)
extent_map_tree_init(&BTRFS_I(inode)->extent_tree); extent_map_tree_init(&BTRFS_I(inode)->extent_tree);
BTRFS_I(inode)->root = btrfs_grab_root(fs_info->tree_root); BTRFS_I(inode)->root = btrfs_grab_root(fs_info->tree_root);
BTRFS_I(inode)->location.objectid = BTRFS_BTREE_INODE_OBJECTID; BTRFS_I(inode)->objectid = BTRFS_BTREE_INODE_OBJECTID;
BTRFS_I(inode)->location.type = 0;
BTRFS_I(inode)->location.offset = 0;
set_bit(BTRFS_INODE_DUMMY, &BTRFS_I(inode)->runtime_flags); set_bit(BTRFS_INODE_DUMMY, &BTRFS_I(inode)->runtime_flags);
__insert_inode_hash(inode, hash); __insert_inode_hash(inode, hash);
fs_info->btree_inode = inode; fs_info->btree_inode = inode;

View File

@ -40,7 +40,7 @@ static int btrfs_encode_fh(struct inode *inode, u32 *fh, int *max_len,
if (parent) { if (parent) {
u64 parent_root_id; u64 parent_root_id;
fid->parent_objectid = BTRFS_I(parent)->location.objectid; fid->parent_objectid = BTRFS_I(parent)->objectid;
fid->parent_gen = parent->i_generation; fid->parent_gen = parent->i_generation;
parent_root_id = btrfs_root_id(BTRFS_I(parent)->root); parent_root_id = btrfs_root_id(BTRFS_I(parent)->root);

View File

@ -3838,7 +3838,7 @@ static int btrfs_read_locked_inode(struct inode *inode,
return -ENOMEM; return -ENOMEM;
} }
memcpy(&location, &BTRFS_I(inode)->location, sizeof(location)); btrfs_get_inode_key(BTRFS_I(inode), &location);
ret = btrfs_lookup_inode(NULL, root, path, &location, 0); ret = btrfs_lookup_inode(NULL, root, path, &location, 0);
if (ret) { if (ret) {
@ -4068,13 +4068,15 @@ static noinline int btrfs_update_inode_item(struct btrfs_trans_handle *trans,
struct btrfs_inode_item *inode_item; struct btrfs_inode_item *inode_item;
struct btrfs_path *path; struct btrfs_path *path;
struct extent_buffer *leaf; struct extent_buffer *leaf;
struct btrfs_key key;
int ret; int ret;
path = btrfs_alloc_path(); path = btrfs_alloc_path();
if (!path) if (!path)
return -ENOMEM; return -ENOMEM;
ret = btrfs_lookup_inode(trans, inode->root, path, &inode->location, 1); btrfs_get_inode_key(inode, &key);
ret = btrfs_lookup_inode(trans, inode->root, path, &key, 1);
if (ret) { if (ret) {
if (ret > 0) if (ret > 0)
ret = -ENOENT; ret = -ENOENT;
@ -4338,7 +4340,7 @@ static int btrfs_unlink_subvol(struct btrfs_trans_handle *trans,
if (btrfs_ino(inode) == BTRFS_FIRST_FREE_OBJECTID) { if (btrfs_ino(inode) == BTRFS_FIRST_FREE_OBJECTID) {
objectid = btrfs_root_id(inode->root); objectid = btrfs_root_id(inode->root);
} else if (btrfs_ino(inode) == BTRFS_EMPTY_SUBVOL_DIR_OBJECTID) { } else if (btrfs_ino(inode) == BTRFS_EMPTY_SUBVOL_DIR_OBJECTID) {
objectid = inode->location.objectid; objectid = inode->objectid;
} else { } else {
WARN_ON(1); WARN_ON(1);
fscrypt_free_filename(&fname); fscrypt_free_filename(&fname);
@ -5580,9 +5582,7 @@ static int btrfs_init_locked_inode(struct inode *inode, void *p)
struct btrfs_iget_args *args = p; struct btrfs_iget_args *args = p;
inode->i_ino = args->ino; inode->i_ino = args->ino;
BTRFS_I(inode)->location.objectid = args->ino; BTRFS_I(inode)->objectid = args->ino;
BTRFS_I(inode)->location.type = BTRFS_INODE_ITEM_KEY;
BTRFS_I(inode)->location.offset = 0;
BTRFS_I(inode)->root = btrfs_grab_root(args->root); BTRFS_I(inode)->root = btrfs_grab_root(args->root);
if (args->root && args->root == args->root->fs_info->tree_root && if (args->root && args->root == args->root->fs_info->tree_root &&
@ -5596,7 +5596,7 @@ static int btrfs_find_actor(struct inode *inode, void *opaque)
{ {
struct btrfs_iget_args *args = opaque; struct btrfs_iget_args *args = opaque;
return args->ino == BTRFS_I(inode)->location.objectid && return args->ino == BTRFS_I(inode)->objectid &&
args->root == BTRFS_I(inode)->root; args->root == BTRFS_I(inode)->root;
} }
@ -5673,7 +5673,8 @@ static struct inode *new_simple_dir(struct inode *dir,
return ERR_PTR(-ENOMEM); return ERR_PTR(-ENOMEM);
BTRFS_I(inode)->root = btrfs_grab_root(root); BTRFS_I(inode)->root = btrfs_grab_root(root);
memcpy(&BTRFS_I(inode)->location, key, sizeof(*key)); BTRFS_I(inode)->objectid = key->objectid;
set_bit(BTRFS_INODE_ROOT_STUB, &BTRFS_I(inode)->runtime_flags);
set_bit(BTRFS_INODE_DUMMY, &BTRFS_I(inode)->runtime_flags); set_bit(BTRFS_INODE_DUMMY, &BTRFS_I(inode)->runtime_flags);
inode->i_ino = BTRFS_EMPTY_SUBVOL_DIR_OBJECTID; inode->i_ino = BTRFS_EMPTY_SUBVOL_DIR_OBJECTID;
@ -6149,7 +6150,7 @@ static int btrfs_insert_inode_locked(struct inode *inode)
{ {
struct btrfs_iget_args args; struct btrfs_iget_args args;
args.ino = BTRFS_I(inode)->location.objectid; args.ino = BTRFS_I(inode)->objectid;
args.root = BTRFS_I(inode)->root; args.root = BTRFS_I(inode)->root;
return insert_inode_locked4(inode, return insert_inode_locked4(inode,
@ -6256,7 +6257,6 @@ int btrfs_create_new_inode(struct btrfs_trans_handle *trans,
struct btrfs_fs_info *fs_info = inode_to_fs_info(dir); struct btrfs_fs_info *fs_info = inode_to_fs_info(dir);
struct btrfs_root *root; struct btrfs_root *root;
struct btrfs_inode_item *inode_item; struct btrfs_inode_item *inode_item;
struct btrfs_key *location;
struct btrfs_path *path; struct btrfs_path *path;
u64 objectid; u64 objectid;
struct btrfs_inode_ref *ref; struct btrfs_inode_ref *ref;
@ -6332,10 +6332,7 @@ int btrfs_create_new_inode(struct btrfs_trans_handle *trans,
BTRFS_INODE_NODATASUM; BTRFS_INODE_NODATASUM;
} }
location = &BTRFS_I(inode)->location; BTRFS_I(inode)->objectid = objectid;
location->objectid = objectid;
location->offset = 0;
location->type = BTRFS_INODE_ITEM_KEY;
ret = btrfs_insert_inode_locked(inode); ret = btrfs_insert_inode_locked(inode);
if (ret < 0) { if (ret < 0) {

View File

@ -1918,7 +1918,7 @@ static int btrfs_search_path_in_tree_user(struct mnt_idmap *idmap,
{ {
struct btrfs_fs_info *fs_info = BTRFS_I(inode)->root->fs_info; struct btrfs_fs_info *fs_info = BTRFS_I(inode)->root->fs_info;
struct super_block *sb = inode->i_sb; struct super_block *sb = inode->i_sb;
struct btrfs_key upper_limit = BTRFS_I(inode)->location; u64 upper_limit = BTRFS_I(inode)->objectid;
u64 treeid = btrfs_root_id(BTRFS_I(inode)->root); u64 treeid = btrfs_root_id(BTRFS_I(inode)->root);
u64 dirid = args->dirid; u64 dirid = args->dirid;
unsigned long item_off; unsigned long item_off;
@ -1944,7 +1944,7 @@ static int btrfs_search_path_in_tree_user(struct mnt_idmap *idmap,
* If the bottom subvolume does not exist directly under upper_limit, * If the bottom subvolume does not exist directly under upper_limit,
* construct the path in from the bottom up. * construct the path in from the bottom up.
*/ */
if (dirid != upper_limit.objectid) { if (dirid != upper_limit) {
ptr = &args->path[BTRFS_INO_LOOKUP_USER_PATH_MAX - 1]; ptr = &args->path[BTRFS_INO_LOOKUP_USER_PATH_MAX - 1];
root = btrfs_get_fs_root(fs_info, treeid, true); root = btrfs_get_fs_root(fs_info, treeid, true);
@ -2019,7 +2019,7 @@ static int btrfs_search_path_in_tree_user(struct mnt_idmap *idmap,
goto out_put; goto out_put;
} }
if (key.offset == upper_limit.objectid) if (key.offset == upper_limit)
break; break;
if (key.objectid == BTRFS_FIRST_FREE_OBJECTID) { if (key.objectid == BTRFS_FIRST_FREE_OBJECTID) {
ret = -EACCES; ret = -EACCES;
@ -2140,7 +2140,7 @@ static int btrfs_ioctl_ino_lookup_user(struct file *file, void __user *argp)
inode = file_inode(file); inode = file_inode(file);
if (args->dirid == BTRFS_FIRST_FREE_OBJECTID && if (args->dirid == BTRFS_FIRST_FREE_OBJECTID &&
BTRFS_I(inode)->location.objectid != BTRFS_FIRST_FREE_OBJECTID) { BTRFS_I(inode)->objectid != BTRFS_FIRST_FREE_OBJECTID) {
/* /*
* The subvolume does not exist under fd with which this is * The subvolume does not exist under fd with which this is
* called * called

View File

@ -62,9 +62,7 @@ struct inode *btrfs_new_test_inode(void)
inode->i_mode = S_IFREG; inode->i_mode = S_IFREG;
inode->i_ino = BTRFS_FIRST_FREE_OBJECTID; inode->i_ino = BTRFS_FIRST_FREE_OBJECTID;
BTRFS_I(inode)->location.type = BTRFS_INODE_ITEM_KEY; BTRFS_I(inode)->objectid = BTRFS_FIRST_FREE_OBJECTID;
BTRFS_I(inode)->location.objectid = BTRFS_FIRST_FREE_OBJECTID;
BTRFS_I(inode)->location.offset = 0;
inode_init_owner(&nop_mnt_idmap, inode, NULL, S_IFREG); inode_init_owner(&nop_mnt_idmap, inode, NULL, S_IFREG);
return inode; return inode;

View File

@ -4254,8 +4254,10 @@ static int log_inode_item(struct btrfs_trans_handle *trans,
struct btrfs_inode *inode, bool inode_item_dropped) struct btrfs_inode *inode, bool inode_item_dropped)
{ {
struct btrfs_inode_item *inode_item; struct btrfs_inode_item *inode_item;
struct btrfs_key key;
int ret; int ret;
btrfs_get_inode_key(inode, &key);
/* /*
* If we are doing a fast fsync and the inode was logged before in the * If we are doing a fast fsync and the inode was logged before in the
* current transaction, then we know the inode was previously logged and * current transaction, then we know the inode was previously logged and
@ -4267,7 +4269,7 @@ static int log_inode_item(struct btrfs_trans_handle *trans,
* already exists can also result in unnecessarily splitting a leaf. * already exists can also result in unnecessarily splitting a leaf.
*/ */
if (!inode_item_dropped && inode->logged_trans == trans->transid) { if (!inode_item_dropped && inode->logged_trans == trans->transid) {
ret = btrfs_search_slot(trans, log, &inode->location, path, 0, 1); ret = btrfs_search_slot(trans, log, &key, path, 0, 1);
ASSERT(ret <= 0); ASSERT(ret <= 0);
if (ret > 0) if (ret > 0)
ret = -ENOENT; ret = -ENOENT;
@ -4281,7 +4283,7 @@ static int log_inode_item(struct btrfs_trans_handle *trans,
* the inode, we set BTRFS_INODE_NEEDS_FULL_SYNC on its runtime * the inode, we set BTRFS_INODE_NEEDS_FULL_SYNC on its runtime
* flags and set ->logged_trans to 0. * flags and set ->logged_trans to 0.
*/ */
ret = btrfs_insert_empty_item(trans, log, path, &inode->location, ret = btrfs_insert_empty_item(trans, log, path, &key,
sizeof(*inode_item)); sizeof(*inode_item));
ASSERT(ret != -EEXIST); ASSERT(ret != -EEXIST);
} }