diff options
Diffstat (limited to 'ubuntu/aufs/i_op_del.c')
-rw-r--r-- | ubuntu/aufs/i_op_del.c | 89 |
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); |