aboutsummaryrefslogtreecommitdiff
path: root/ubuntu/aufs/i_op_add.c
diff options
context:
space:
mode:
Diffstat (limited to 'ubuntu/aufs/i_op_add.c')
-rw-r--r--ubuntu/aufs/i_op_add.c88
1 files changed, 57 insertions, 31 deletions
diff --git a/ubuntu/aufs/i_op_add.c b/ubuntu/aufs/i_op_add.c
index 18635718325..cd11360361d 100644
--- a/ubuntu/aufs/i_op_add.c
+++ b/ubuntu/aufs/i_op_add.c
@@ -81,6 +81,18 @@ out:
return err;
}
+static int au_d_may_add(struct dentry *dentry)
+{
+ int err;
+
+ err = 0;
+ if (unlikely(d_unhashed(dentry)))
+ err = -ENOENT;
+ if (unlikely(dentry->d_inode))
+ err = -EEXIST;
+ return err;
+}
+
/*
* simple tests for the adding inode operations.
* following the checks in vfs, plus the parent-child relationship.
@@ -236,13 +248,18 @@ static int add_simple(struct inode *dir, struct dentry *dentry,
IMustLock(dir);
parent = dentry->d_parent; /* dir inode is locked */
- aufs_read_lock(dentry, AuLock_DW);
+ err = aufs_read_lock(dentry, AuLock_DW | AuLock_GEN);
+ if (unlikely(err))
+ goto out;
+ err = au_d_may_add(dentry);
+ if (unlikely(err))
+ goto out_unlock;
di_write_lock_parent(parent);
wh_dentry = lock_hdir_lkup_wh(dentry, &dt, /*src_dentry*/NULL, &pin,
&wr_dir_args);
err = PTR_ERR(wh_dentry);
if (IS_ERR(wh_dentry))
- goto out;
+ goto out_parent;
bstart = au_dbstart(dentry);
h_path.dentry = au_h_dptr(dentry, bstart);
@@ -275,19 +292,20 @@ static int add_simple(struct inode *dir, struct dentry *dentry,
err = -EIO;
}
au_dtime_revert(&dt);
- d_drop(dentry);
}
au_unpin(&pin);
dput(wh_dentry);
-out:
+out_parent:
+ di_write_unlock(parent);
+out_unlock:
if (unlikely(err)) {
au_update_dbstart(dentry);
d_drop(dentry);
}
- di_write_unlock(parent);
aufs_read_unlock(dentry, AuLock_DW);
+out:
return err;
}
@@ -456,19 +474,22 @@ int aufs_link(struct dentry *src_dentry, struct inode *dir,
inode = src_dentry->d_inode;
IMustLock(inode);
- err = -ENOENT;
- if (unlikely(!inode->i_nlink))
- goto out;
-
err = -ENOMEM;
a = kzalloc(sizeof(*a), GFP_NOFS);
if (unlikely(!a))
goto out;
a->parent = dentry->d_parent; /* dir inode is locked */
- err = aufs_read_and_write_lock2(dentry, src_dentry, AuLock_NOPLM);
+ err = aufs_read_and_write_lock2(dentry, src_dentry,
+ AuLock_NOPLM | AuLock_GEN);
if (unlikely(err))
goto out_kfree;
+ err = au_d_hashed_positive(src_dentry);
+ if (unlikely(err))
+ goto out_unlock;
+ err = au_d_may_add(dentry);
+ if (unlikely(err))
+ goto out_unlock;
a->src_parent = dget_parent(src_dentry);
wr_dir_args.force_btgt = au_dbstart(src_dentry);
@@ -479,7 +500,7 @@ int aufs_link(struct dentry *src_dentry, struct inode *dir,
&wr_dir_args);
err = PTR_ERR(wh_dentry);
if (IS_ERR(wh_dentry))
- goto out_unlock;
+ goto out_parent;
err = 0;
sb = dentry->d_sb;
@@ -539,34 +560,32 @@ int aufs_link(struct dentry *src_dentry, struct inode *dir,
au_cpup_attr_timesizes(dir);
inc_nlink(inode);
inode->i_ctime = dir->i_ctime;
- if (!d_unhashed(a->h_path.dentry))
- d_instantiate(dentry, au_igrab(inode));
- else
+ d_instantiate(dentry, au_igrab(inode));
+ if (d_unhashed(a->h_path.dentry))
/* some filesystem calls d_drop() */
d_drop(dentry);
goto out_unpin; /* success */
out_revert:
rerr = vfsub_unlink(au_pinned_h_dir(&a->pin), &a->h_path, /*force*/0);
- if (!rerr)
- goto out_dt;
- AuIOErr("%.*s reverting failed(%d, %d)\n",
- AuDLNPair(dentry), err, rerr);
- err = -EIO;
-out_dt:
- d_drop(dentry);
+ if (unlikely(rerr)) {
+ AuIOErr("%.*s reverting failed(%d, %d)\n",
+ AuDLNPair(dentry), err, rerr);
+ err = -EIO;
+ }
au_dtime_revert(&dt);
out_unpin:
au_unpin(&a->pin);
out_wh:
dput(wh_dentry);
+out_parent:
+ di_write_unlock(a->parent);
+ dput(a->src_parent);
out_unlock:
if (unlikely(err)) {
au_update_dbstart(dentry);
d_drop(dentry);
}
- di_write_unlock(a->parent);
- dput(a->src_parent);
aufs_read_and_write_unlock2(dentry, src_dentry);
out_kfree:
kfree(a);
@@ -599,14 +618,20 @@ int aufs_mkdir(struct inode *dir, struct dentry *dentry, int mode)
if (unlikely(!a))
goto out;
- aufs_read_lock(dentry, AuLock_DW);
+ err = aufs_read_lock(dentry, AuLock_DW | AuLock_GEN);
+ if (unlikely(err))
+ goto out_free;
+ err = au_d_may_add(dentry);
+ if (unlikely(err))
+ goto out_unlock;
+
parent = dentry->d_parent; /* dir inode is locked */
di_write_lock_parent(parent);
wh_dentry = lock_hdir_lkup_wh(dentry, &a->dt, /*src_dentry*/NULL,
&a->pin, &wr_dir_args);
err = PTR_ERR(wh_dentry);
if (IS_ERR(wh_dentry))
- goto out_free;
+ goto out_parent;
sb = dentry->d_sb;
bindex = au_dbstart(dentry);
@@ -614,7 +639,7 @@ int aufs_mkdir(struct inode *dir, struct dentry *dentry, int mode)
h_path.mnt = au_sbr_mnt(sb, bindex);
err = vfsub_mkdir(au_pinned_h_dir(&a->pin), &h_path, mode);
if (unlikely(err))
- goto out_unlock;
+ goto out_unpin;
/* make the dir opaque */
diropq = 0;
@@ -634,7 +659,7 @@ int aufs_mkdir(struct inode *dir, struct dentry *dentry, int mode)
err = epilog(dir, bindex, wh_dentry, dentry);
if (!err) {
inc_nlink(dir);
- goto out_unlock; /* success */
+ goto out_unpin; /* success */
}
/* revert */
@@ -658,18 +683,19 @@ out_dir:
AuDLNPair(dentry), err, rerr);
err = -EIO;
}
- d_drop(dentry);
au_dtime_revert(&a->dt);
-out_unlock:
+out_unpin:
au_unpin(&a->pin);
dput(wh_dentry);
-out_free:
+out_parent:
+ di_write_unlock(parent);
+out_unlock:
if (unlikely(err)) {
au_update_dbstart(dentry);
d_drop(dentry);
}
- di_write_unlock(parent);
aufs_read_unlock(dentry, AuLock_DW);
+out_free:
kfree(a);
out:
return err;