aboutsummaryrefslogtreecommitdiff
path: root/ubuntu/aufs/i_op_del.c
diff options
context:
space:
mode:
Diffstat (limited to 'ubuntu/aufs/i_op_del.c')
-rw-r--r--ubuntu/aufs/i_op_del.c89
1 files changed, 49 insertions, 40 deletions
diff --git a/ubuntu/aufs/i_op_del.c b/ubuntu/aufs/i_op_del.c
index 5b31bbd88767..1019bf91aead 100644
--- a/ubuntu/aufs/i_op_del.c
+++ b/ubuntu/aufs/i_op_del.c
@@ -59,24 +59,20 @@ int au_wr_dir_need_wh(struct dentry *dentry, int isdir, aufs_bindex_t *bcpup)
goto out;
need_wh = 1;
} else {
- aufs_bindex_t old_bend, new_bend, bdiropq = -1;
-
- old_bend = au_dbend(dentry);
- if (isdir) {
- bdiropq = au_dbdiropq(dentry);
- au_set_dbdiropq(dentry, -1);
- }
- need_wh = au_lkup_dentry(dentry, bstart + 1, /*type*/0,
- /*nd*/NULL);
- err = need_wh;
- if (isdir)
- au_set_dbdiropq(dentry, bdiropq);
- if (unlikely(err < 0))
- goto out;
- new_bend = au_dbend(dentry);
- if (!need_wh && old_bend != new_bend) {
- au_set_h_dptr(dentry, new_bend, NULL);
- au_set_dbend(dentry, old_bend);
+ struct au_dinfo *dinfo, *tmp;
+
+ need_wh = -ENOMEM;
+ dinfo = au_di(dentry);
+ tmp = au_di_alloc(sb, AuLsc_DI_TMP);
+ if (tmp) {
+ au_di_cp(tmp, dinfo);
+ au_di_swap(tmp, dinfo);
+ /* returns the number of positive dentries */
+ need_wh = au_lkup_dentry(dentry, bstart + 1, /*type*/0,
+ /*nd*/NULL);
+ au_di_swap(tmp, dinfo);
+ au_rw_write_unlock(&tmp->di_rwsem);
+ au_di_free(tmp);
}
}
AuDbg("need_wh %d\n", need_wh);
@@ -268,10 +264,6 @@ static void epilog(struct inode *dir, struct dentry *dentry,
d_drop(dentry);
inode->i_ctime = dir->i_ctime;
- if (atomic_read(&dentry->d_count) == 1) {
- au_set_h_dptr(dentry, au_dbstart(dentry), NULL);
- au_update_dbstart(dentry);
- }
if (au_ibstart(dir) == bindex)
au_cpup_attr_timesizes(dir);
dir->i_version++;
@@ -315,22 +307,28 @@ int aufs_unlink(struct inode *dir, struct dentry *dentry)
struct dentry *parent, *wh_dentry;
IMustLock(dir);
+
+ err = aufs_read_lock(dentry, AuLock_DW | AuLock_GEN);
+ if (unlikely(err))
+ goto out;
+ err = au_d_hashed_positive(dentry);
+ if (unlikely(err))
+ goto out_unlock;
inode = dentry->d_inode;
- if (unlikely(!inode))
- return -ENOENT; /* possible? */
IMustLock(inode);
-
- aufs_read_lock(dentry, AuLock_DW);
- parent = dentry->d_parent; /* dir inode is locked */
- di_write_lock_parent(parent);
+ err = -EISDIR;
+ if (unlikely(S_ISDIR(inode->i_mode)))
+ goto out_unlock; /* possible? */
bstart = au_dbstart(dentry);
bwh = au_dbwh(dentry);
bindex = -1;
+ parent = dentry->d_parent; /* dir inode is locked */
+ di_write_lock_parent(parent);
wh_dentry = lock_hdir_create_wh(dentry, /*isdir*/0, &bindex, &dt, &pin);
err = PTR_ERR(wh_dentry);
if (IS_ERR(wh_dentry))
- goto out;
+ goto out_parent;
h_path.mnt = au_sbr_mnt(dentry->d_sb, bstart);
h_path.dentry = au_h_dptr(dentry, bstart);
@@ -356,7 +354,7 @@ int aufs_unlink(struct inode *dir, struct dentry *dentry)
} else
/* todo: this timestamp may be reverted later */
inode->i_ctime = h_dir->i_ctime;
- goto out_unlock; /* success */
+ goto out_unpin; /* success */
}
/* revert */
@@ -368,13 +366,15 @@ int aufs_unlink(struct inode *dir, struct dentry *dentry)
err = rerr;
}
-out_unlock:
+out_unpin:
au_unpin(&pin);
dput(wh_dentry);
dput(h_path.dentry);
-out:
+out_parent:
di_write_unlock(parent);
+out_unlock:
aufs_read_unlock(dentry, AuLock_DW);
+out:
return err;
}
@@ -389,13 +389,22 @@ int aufs_rmdir(struct inode *dir, struct dentry *dentry)
struct au_whtmp_rmdir *args;
IMustLock(dir);
- inode = dentry->d_inode;
- err = -ENOENT; /* possible? */
- if (unlikely(!inode))
+
+ err = aufs_read_lock(dentry, AuLock_DW | AuLock_FLUSH | AuLock_GEN);
+ if (unlikely(err))
goto out;
+
+ /* VFS already unhashes it */
+ inode = dentry->d_inode;
+ err = -ENOENT;
+ if (unlikely(!inode || !inode->i_nlink
+ || IS_DEADDIR(inode)))
+ goto out_unlock;
IMustLock(inode);
+ err = -ENOTDIR;
+ if (unlikely(!S_ISDIR(inode->i_mode)))
+ goto out_unlock; /* possible? */
- aufs_read_lock(dentry, AuLock_DW | AuLock_FLUSH);
err = -ENOMEM;
args = au_whtmp_rmdir_alloc(dir->i_sb, GFP_NOFS);
if (unlikely(!args))
@@ -405,7 +414,7 @@ int aufs_rmdir(struct inode *dir, struct dentry *dentry)
di_write_lock_parent(parent);
err = au_test_empty(dentry, &args->whlist);
if (unlikely(err))
- goto out_args;
+ goto out_parent;
bstart = au_dbstart(dentry);
bwh = au_dbwh(dentry);
@@ -413,7 +422,7 @@ int aufs_rmdir(struct inode *dir, struct dentry *dentry)
wh_dentry = lock_hdir_create_wh(dentry, /*isdir*/1, &bindex, &dt, &pin);
err = PTR_ERR(wh_dentry);
if (IS_ERR(wh_dentry))
- goto out_args;
+ goto out_parent;
h_dentry = au_h_dptr(dentry, bstart);
dget(h_dentry);
@@ -434,7 +443,7 @@ int aufs_rmdir(struct inode *dir, struct dentry *dentry)
}
if (!err) {
- clear_nlink(inode);
+ vfsub_dead_dir(inode);
au_set_dbdiropq(dentry, -1);
epilog(dir, dentry, bindex);
@@ -460,7 +469,7 @@ out_unpin:
au_unpin(&pin);
dput(wh_dentry);
dput(h_dentry);
-out_args:
+out_parent:
di_write_unlock(parent);
if (args)
au_whtmp_rmdir_free(args);