|
@@ -1227,7 +1227,7 @@ static struct buffer_head * ext4_find_entry (struct inode *dir,
|
|
buffer */
|
|
buffer */
|
|
int num = 0;
|
|
int num = 0;
|
|
ext4_lblk_t nblocks;
|
|
ext4_lblk_t nblocks;
|
|
- int i, err;
|
|
|
|
|
|
+ int i, err = 0;
|
|
int namelen;
|
|
int namelen;
|
|
|
|
|
|
*res_dir = NULL;
|
|
*res_dir = NULL;
|
|
@@ -1264,7 +1264,11 @@ static struct buffer_head * ext4_find_entry (struct inode *dir,
|
|
* return. Otherwise, fall back to doing a search the
|
|
* return. Otherwise, fall back to doing a search the
|
|
* old fashioned way.
|
|
* old fashioned way.
|
|
*/
|
|
*/
|
|
- if (bh || (err != ERR_BAD_DX_DIR))
|
|
|
|
|
|
+ if (err == -ENOENT)
|
|
|
|
+ return NULL;
|
|
|
|
+ if (err && err != ERR_BAD_DX_DIR)
|
|
|
|
+ return ERR_PTR(err);
|
|
|
|
+ if (bh)
|
|
return bh;
|
|
return bh;
|
|
dxtrace(printk(KERN_DEBUG "ext4_find_entry: dx failed, "
|
|
dxtrace(printk(KERN_DEBUG "ext4_find_entry: dx failed, "
|
|
"falling back\n"));
|
|
"falling back\n"));
|
|
@@ -1295,6 +1299,11 @@ restart:
|
|
}
|
|
}
|
|
num++;
|
|
num++;
|
|
bh = ext4_getblk(NULL, dir, b++, 0, &err);
|
|
bh = ext4_getblk(NULL, dir, b++, 0, &err);
|
|
|
|
+ if (unlikely(err)) {
|
|
|
|
+ if (ra_max == 0)
|
|
|
|
+ return ERR_PTR(err);
|
|
|
|
+ break;
|
|
|
|
+ }
|
|
bh_use[ra_max] = bh;
|
|
bh_use[ra_max] = bh;
|
|
if (bh)
|
|
if (bh)
|
|
ll_rw_block(READ | REQ_META | REQ_PRIO,
|
|
ll_rw_block(READ | REQ_META | REQ_PRIO,
|
|
@@ -1417,6 +1426,8 @@ static struct dentry *ext4_lookup(struct inode *dir, struct dentry *dentry, unsi
|
|
return ERR_PTR(-ENAMETOOLONG);
|
|
return ERR_PTR(-ENAMETOOLONG);
|
|
|
|
|
|
bh = ext4_find_entry(dir, &dentry->d_name, &de, NULL);
|
|
bh = ext4_find_entry(dir, &dentry->d_name, &de, NULL);
|
|
|
|
+ if (IS_ERR(bh))
|
|
|
|
+ return (struct dentry *) bh;
|
|
inode = NULL;
|
|
inode = NULL;
|
|
if (bh) {
|
|
if (bh) {
|
|
__u32 ino = le32_to_cpu(de->inode);
|
|
__u32 ino = le32_to_cpu(de->inode);
|
|
@@ -1450,6 +1461,8 @@ struct dentry *ext4_get_parent(struct dentry *child)
|
|
struct buffer_head *bh;
|
|
struct buffer_head *bh;
|
|
|
|
|
|
bh = ext4_find_entry(child->d_inode, &dotdot, &de, NULL);
|
|
bh = ext4_find_entry(child->d_inode, &dotdot, &de, NULL);
|
|
|
|
+ if (IS_ERR(bh))
|
|
|
|
+ return (struct dentry *) bh;
|
|
if (!bh)
|
|
if (!bh)
|
|
return ERR_PTR(-ENOENT);
|
|
return ERR_PTR(-ENOENT);
|
|
ino = le32_to_cpu(de->inode);
|
|
ino = le32_to_cpu(de->inode);
|
|
@@ -2727,6 +2740,8 @@ static int ext4_rmdir(struct inode *dir, struct dentry *dentry)
|
|
|
|
|
|
retval = -ENOENT;
|
|
retval = -ENOENT;
|
|
bh = ext4_find_entry(dir, &dentry->d_name, &de, NULL);
|
|
bh = ext4_find_entry(dir, &dentry->d_name, &de, NULL);
|
|
|
|
+ if (IS_ERR(bh))
|
|
|
|
+ return PTR_ERR(bh);
|
|
if (!bh)
|
|
if (!bh)
|
|
goto end_rmdir;
|
|
goto end_rmdir;
|
|
|
|
|
|
@@ -2794,6 +2809,8 @@ static int ext4_unlink(struct inode *dir, struct dentry *dentry)
|
|
|
|
|
|
retval = -ENOENT;
|
|
retval = -ENOENT;
|
|
bh = ext4_find_entry(dir, &dentry->d_name, &de, NULL);
|
|
bh = ext4_find_entry(dir, &dentry->d_name, &de, NULL);
|
|
|
|
+ if (IS_ERR(bh))
|
|
|
|
+ return PTR_ERR(bh);
|
|
if (!bh)
|
|
if (!bh)
|
|
goto end_unlink;
|
|
goto end_unlink;
|
|
|
|
|
|
@@ -3121,6 +3138,8 @@ static int ext4_find_delete_entry(handle_t *handle, struct inode *dir,
|
|
struct ext4_dir_entry_2 *de;
|
|
struct ext4_dir_entry_2 *de;
|
|
|
|
|
|
bh = ext4_find_entry(dir, d_name, &de, NULL);
|
|
bh = ext4_find_entry(dir, d_name, &de, NULL);
|
|
|
|
+ if (IS_ERR(bh))
|
|
|
|
+ return PTR_ERR(bh);
|
|
if (bh) {
|
|
if (bh) {
|
|
retval = ext4_delete_entry(handle, dir, de, bh);
|
|
retval = ext4_delete_entry(handle, dir, de, bh);
|
|
brelse(bh);
|
|
brelse(bh);
|
|
@@ -3128,7 +3147,8 @@ static int ext4_find_delete_entry(handle_t *handle, struct inode *dir,
|
|
return retval;
|
|
return retval;
|
|
}
|
|
}
|
|
|
|
|
|
-static void ext4_rename_delete(handle_t *handle, struct ext4_renament *ent)
|
|
|
|
|
|
+static void ext4_rename_delete(handle_t *handle, struct ext4_renament *ent,
|
|
|
|
+ int force_reread)
|
|
{
|
|
{
|
|
int retval;
|
|
int retval;
|
|
/*
|
|
/*
|
|
@@ -3140,7 +3160,8 @@ static void ext4_rename_delete(handle_t *handle, struct ext4_renament *ent)
|
|
if (le32_to_cpu(ent->de->inode) != ent->inode->i_ino ||
|
|
if (le32_to_cpu(ent->de->inode) != ent->inode->i_ino ||
|
|
ent->de->name_len != ent->dentry->d_name.len ||
|
|
ent->de->name_len != ent->dentry->d_name.len ||
|
|
strncmp(ent->de->name, ent->dentry->d_name.name,
|
|
strncmp(ent->de->name, ent->dentry->d_name.name,
|
|
- ent->de->name_len)) {
|
|
|
|
|
|
+ ent->de->name_len) ||
|
|
|
|
+ force_reread) {
|
|
retval = ext4_find_delete_entry(handle, ent->dir,
|
|
retval = ext4_find_delete_entry(handle, ent->dir,
|
|
&ent->dentry->d_name);
|
|
&ent->dentry->d_name);
|
|
} else {
|
|
} else {
|
|
@@ -3191,6 +3212,7 @@ static int ext4_rename(struct inode *old_dir, struct dentry *old_dentry,
|
|
.dentry = new_dentry,
|
|
.dentry = new_dentry,
|
|
.inode = new_dentry->d_inode,
|
|
.inode = new_dentry->d_inode,
|
|
};
|
|
};
|
|
|
|
+ int force_reread;
|
|
int retval;
|
|
int retval;
|
|
|
|
|
|
dquot_initialize(old.dir);
|
|
dquot_initialize(old.dir);
|
|
@@ -3202,6 +3224,8 @@ static int ext4_rename(struct inode *old_dir, struct dentry *old_dentry,
|
|
dquot_initialize(new.inode);
|
|
dquot_initialize(new.inode);
|
|
|
|
|
|
old.bh = ext4_find_entry(old.dir, &old.dentry->d_name, &old.de, NULL);
|
|
old.bh = ext4_find_entry(old.dir, &old.dentry->d_name, &old.de, NULL);
|
|
|
|
+ if (IS_ERR(old.bh))
|
|
|
|
+ return PTR_ERR(old.bh);
|
|
/*
|
|
/*
|
|
* Check for inode number is _not_ due to possible IO errors.
|
|
* Check for inode number is _not_ due to possible IO errors.
|
|
* We might rmdir the source, keep it as pwd of some process
|
|
* We might rmdir the source, keep it as pwd of some process
|
|
@@ -3214,6 +3238,10 @@ static int ext4_rename(struct inode *old_dir, struct dentry *old_dentry,
|
|
|
|
|
|
new.bh = ext4_find_entry(new.dir, &new.dentry->d_name,
|
|
new.bh = ext4_find_entry(new.dir, &new.dentry->d_name,
|
|
&new.de, &new.inlined);
|
|
&new.de, &new.inlined);
|
|
|
|
+ if (IS_ERR(new.bh)) {
|
|
|
|
+ retval = PTR_ERR(new.bh);
|
|
|
|
+ goto end_rename;
|
|
|
|
+ }
|
|
if (new.bh) {
|
|
if (new.bh) {
|
|
if (!new.inode) {
|
|
if (!new.inode) {
|
|
brelse(new.bh);
|
|
brelse(new.bh);
|
|
@@ -3246,6 +3274,15 @@ static int ext4_rename(struct inode *old_dir, struct dentry *old_dentry,
|
|
if (retval)
|
|
if (retval)
|
|
goto end_rename;
|
|
goto end_rename;
|
|
}
|
|
}
|
|
|
|
+ /*
|
|
|
|
+ * If we're renaming a file within an inline_data dir and adding or
|
|
|
|
+ * setting the new dirent causes a conversion from inline_data to
|
|
|
|
+ * extents/blockmap, we need to force the dirent delete code to
|
|
|
|
+ * re-read the directory, or else we end up trying to delete a dirent
|
|
|
|
+ * from what is now the extent tree root (or a block map).
|
|
|
|
+ */
|
|
|
|
+ force_reread = (new.dir->i_ino == old.dir->i_ino &&
|
|
|
|
+ ext4_test_inode_flag(new.dir, EXT4_INODE_INLINE_DATA));
|
|
if (!new.bh) {
|
|
if (!new.bh) {
|
|
retval = ext4_add_entry(handle, new.dentry, old.inode);
|
|
retval = ext4_add_entry(handle, new.dentry, old.inode);
|
|
if (retval)
|
|
if (retval)
|
|
@@ -3256,6 +3293,9 @@ static int ext4_rename(struct inode *old_dir, struct dentry *old_dentry,
|
|
if (retval)
|
|
if (retval)
|
|
goto end_rename;
|
|
goto end_rename;
|
|
}
|
|
}
|
|
|
|
+ if (force_reread)
|
|
|
|
+ force_reread = !ext4_test_inode_flag(new.dir,
|
|
|
|
+ EXT4_INODE_INLINE_DATA);
|
|
|
|
|
|
/*
|
|
/*
|
|
* Like most other Unix systems, set the ctime for inodes on a
|
|
* Like most other Unix systems, set the ctime for inodes on a
|
|
@@ -3267,7 +3307,7 @@ static int ext4_rename(struct inode *old_dir, struct dentry *old_dentry,
|
|
/*
|
|
/*
|
|
* ok, that's it
|
|
* ok, that's it
|
|
*/
|
|
*/
|
|
- ext4_rename_delete(handle, &old);
|
|
|
|
|
|
+ ext4_rename_delete(handle, &old, force_reread);
|
|
|
|
|
|
if (new.inode) {
|
|
if (new.inode) {
|
|
ext4_dec_count(handle, new.inode);
|
|
ext4_dec_count(handle, new.inode);
|
|
@@ -3330,6 +3370,8 @@ static int ext4_cross_rename(struct inode *old_dir, struct dentry *old_dentry,
|
|
|
|
|
|
old.bh = ext4_find_entry(old.dir, &old.dentry->d_name,
|
|
old.bh = ext4_find_entry(old.dir, &old.dentry->d_name,
|
|
&old.de, &old.inlined);
|
|
&old.de, &old.inlined);
|
|
|
|
+ if (IS_ERR(old.bh))
|
|
|
|
+ return PTR_ERR(old.bh);
|
|
/*
|
|
/*
|
|
* Check for inode number is _not_ due to possible IO errors.
|
|
* Check for inode number is _not_ due to possible IO errors.
|
|
* We might rmdir the source, keep it as pwd of some process
|
|
* We might rmdir the source, keep it as pwd of some process
|
|
@@ -3342,6 +3384,10 @@ static int ext4_cross_rename(struct inode *old_dir, struct dentry *old_dentry,
|
|
|
|
|
|
new.bh = ext4_find_entry(new.dir, &new.dentry->d_name,
|
|
new.bh = ext4_find_entry(new.dir, &new.dentry->d_name,
|
|
&new.de, &new.inlined);
|
|
&new.de, &new.inlined);
|
|
|
|
+ if (IS_ERR(new.bh)) {
|
|
|
|
+ retval = PTR_ERR(new.bh);
|
|
|
|
+ goto end_rename;
|
|
|
|
+ }
|
|
|
|
|
|
/* RENAME_EXCHANGE case: old *and* new must both exist */
|
|
/* RENAME_EXCHANGE case: old *and* new must both exist */
|
|
if (!new.bh || le32_to_cpu(new.de->inode) != new.inode->i_ino)
|
|
if (!new.bh || le32_to_cpu(new.de->inode) != new.inode->i_ino)
|