From: Yan Zheng <zheng.yan@oracle.com>
To: chris Mason <chris.mason@oracle.com>, linux-btrfs@vger.kernel.org
Subject: [PATCH] check size of inode backref before adding hardlink
Date: Wed, 05 Aug 2009 17:13:42 +0800 [thread overview]
Message-ID: <4A794D46.1050500@oracle.com> (raw)
For every hardlink in btrfs, there is a corresponding inode back
reference. All inode back references for hardlinks in a given
directory are stored in single b-tree item. The size of b-tree item
is limited by the size of b-tree leaf, so we can only create limited
number of hardlinks to a given file in a directory.
The original code lacks of the check, it oops if the number of
hardlinks goes over the limit. This patch fixes the issue by adding
the check to btrfs_link and btrfs_rename.
Signed-off-by: Yan Zheng <zheng.yan@oracle.com>
---
diff -urp 1/fs/btrfs/ctree.c 2/fs/btrfs/ctree.c
--- 1/fs/btrfs/ctree.c 2009-07-29 10:03:04.150859426 +0800
+++ 2/fs/btrfs/ctree.c 2009-08-05 14:55:01.850810000 +0800
@@ -2853,6 +2853,12 @@ static noinline int split_leaf(struct bt
int split;
int num_doubles = 0;
+ l = path->nodes[0];
+ slot = path->slots[0];
+ if (extend && data_size + btrfs_item_size_nr(l, slot) +
+ sizeof(struct btrfs_item) > BTRFS_LEAF_DATA_SIZE(root))
+ return -EOVERFLOW;
+
/* first try to make some room by pushing left and right */
if (data_size && ins_key->type != BTRFS_DIR_ITEM_KEY) {
wret = push_leaf_right(trans, root, path, data_size, 0);
diff -urp 1/fs/btrfs/inode.c 2/fs/btrfs/inode.c
--- 1/fs/btrfs/inode.c 2009-07-29 10:03:04.365858071 +0800
+++ 2/fs/btrfs/inode.c 2009-08-05 16:06:24.220810000 +0800
@@ -3674,7 +3674,7 @@ int btrfs_add_link(struct btrfs_trans_ha
struct inode *parent_inode, struct inode *inode,
const char *name, int name_len, int add_backref, u64 index)
{
- int ret;
+ int ret = 0;
struct btrfs_key key;
struct btrfs_root *root = BTRFS_I(parent_inode)->root;
@@ -3682,18 +3682,18 @@ int btrfs_add_link(struct btrfs_trans_ha
btrfs_set_key_type(&key, BTRFS_INODE_ITEM_KEY);
key.offset = 0;
- ret = btrfs_insert_dir_item(trans, root, name, name_len,
- parent_inode->i_ino,
- &key, btrfs_inode_type(inode),
- index);
+ if (add_backref) {
+ ret = btrfs_insert_inode_ref(trans, root,
+ name, name_len, inode->i_ino,
+ parent_inode->i_ino, index);
+ }
+
if (ret == 0) {
- if (add_backref) {
- ret = btrfs_insert_inode_ref(trans, root,
- name, name_len,
- inode->i_ino,
- parent_inode->i_ino,
- index);
- }
+ ret = btrfs_insert_dir_item(trans, root, name, name_len,
+ parent_inode->i_ino, &key,
+ btrfs_inode_type(inode), index);
+ BUG_ON(ret);
+
btrfs_i_size_write(parent_inode, parent_inode->i_size +
name_len * 2);
parent_inode->i_mtime = parent_inode->i_ctime = CURRENT_TIME;
@@ -3877,20 +3877,16 @@ static int btrfs_link(struct dentry *old
atomic_inc(&inode->i_count);
err = btrfs_add_nondir(trans, dentry, inode, 1, index);
-
- if (err)
- drop_inode = 1;
-
- dir->i_sb->s_dirt = 1;
- btrfs_update_inode_block_group(trans, dir);
- err = btrfs_update_inode(trans, root, inode);
-
if (err)
drop_inode = 1;
+ else {
+ dir->i_sb->s_dirt = 1;
+ btrfs_update_inode_block_group(trans, dir);
+ btrfs_update_inode(trans, root, inode);
+ btrfs_log_new_name(trans, inode, NULL, dentry->d_parent);
+ }
nr = trans->blocks_used;
-
- btrfs_log_new_name(trans, inode, NULL, dentry->d_parent);
btrfs_end_transaction_throttle(trans, root);
fail:
if (drop_inode) {
@@ -4833,6 +4829,16 @@ static int btrfs_rename(struct inode *ol
btrfs_set_trans_block_group(trans, new_dir);
+ ret = btrfs_set_inode_index(new_dir, &index);
+ if (ret)
+ goto out_fail;
+
+ ret = btrfs_insert_inode_ref(trans, root, new_dentry->d_name.name,
+ new_dentry->d_name.len, old_inode->i_ino,
+ new_dir->i_ino, index);
+ if (ret)
+ goto out_fail;
+
btrfs_inc_nlink(old_dentry->d_inode);
old_dir->i_ctime = old_dir->i_mtime = ctime;
new_dir->i_ctime = new_dir->i_mtime = ctime;
@@ -4844,8 +4850,7 @@ static int btrfs_rename(struct inode *ol
ret = btrfs_unlink_inode(trans, root, old_dir, old_dentry->d_inode,
old_dentry->d_name.name,
old_dentry->d_name.len);
- if (ret)
- goto out_fail;
+ BUG_ON(ret);
if (new_inode) {
new_inode->i_ctime = CURRENT_TIME;
@@ -4853,24 +4858,17 @@ static int btrfs_rename(struct inode *ol
new_dentry->d_inode,
new_dentry->d_name.name,
new_dentry->d_name.len);
- if (ret)
- goto out_fail;
+ BUG_ON(ret);
if (new_inode->i_nlink == 0) {
ret = btrfs_orphan_add(trans, new_dentry->d_inode);
- if (ret)
- goto out_fail;
+ BUG_ON(ret);
}
-
}
- ret = btrfs_set_inode_index(new_dir, &index);
- if (ret)
- goto out_fail;
ret = btrfs_add_link(trans, new_dentry->d_parent->d_inode,
old_inode, new_dentry->d_name.name,
- new_dentry->d_name.len, 1, index);
- if (ret)
- goto out_fail;
+ new_dentry->d_name.len, 0, index);
+ BUG_ON(ret);
btrfs_log_new_name(trans, old_inode, old_dir,
new_dentry->d_parent);
diff -urp 1/fs/btrfs/inode-item.c 2/fs/btrfs/inode-item.c
--- 1/fs/btrfs/inode-item.c 2009-07-24 09:51:38.372057017 +0800
+++ 2/fs/btrfs/inode-item.c 2009-08-05 15:11:37.141061000 +0800
@@ -149,6 +149,8 @@ int btrfs_insert_inode_ref(struct btrfs_
ptr = (unsigned long)(ref + 1);
ret = 0;
} else if (ret < 0) {
+ if (ret == -EOVERFLOW)
+ ret = -EMLINK;
goto out;
} else {
ref = btrfs_item_ptr(path->nodes[0], path->slots[0],
next reply other threads:[~2009-08-05 9:13 UTC|newest]
Thread overview: 2+ messages / expand[flat|nested] mbox.gz Atom feed top
2009-08-05 9:13 Yan Zheng [this message]
-- strict thread matches above, loose matches on Subject: below --
2009-09-24 9:08 [PATCH] check size of inode backref before adding hardlink Yan, Zheng
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=4A794D46.1050500@oracle.com \
--to=zheng.yan@oracle.com \
--cc=chris.mason@oracle.com \
--cc=linux-btrfs@vger.kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.