aboutsummaryrefslogtreecommitdiff
path: root/ubuntu/aufs/file.c
diff options
context:
space:
mode:
Diffstat (limited to 'ubuntu/aufs/file.c')
-rw-r--r--ubuntu/aufs/file.c83
1 files changed, 52 insertions, 31 deletions
diff --git a/ubuntu/aufs/file.c b/ubuntu/aufs/file.c
index 15e38ce31c6f..2ba0c000f169 100644
--- a/ubuntu/aufs/file.c
+++ b/ubuntu/aufs/file.c
@@ -65,7 +65,7 @@ struct file *au_h_open(struct dentry *dentry, aufs_bindex_t bindex, int flags,
h_file = ERR_PTR(-EACCES);
exec_flag = flags & vfsub_fmode_to_uint(FMODE_EXEC);
if (exec_flag && (br->br_mnt->mnt_flags & MNT_NOEXEC))
- goto out;
+ goto out;
/* drop flags for writing */
if (au_test_ro(sb, bindex, dentry->d_inode))
@@ -202,14 +202,20 @@ static int au_ready_to_write_wh(struct file *file, loff_t len,
aufs_bindex_t bcpup)
{
int err;
- struct inode *inode;
- struct dentry *dentry, *hi_wh;
+ struct inode *inode, *h_inode;
+ struct dentry *dentry, *h_dentry, *hi_wh;
dentry = file->f_dentry;
au_update_dbstart(dentry);
inode = dentry->d_inode;
+ h_inode = NULL;
+ if (au_dbstart(dentry) <= bcpup && au_dbend(dentry) >= bcpup) {
+ h_dentry = au_h_dptr(dentry, bcpup);
+ if (h_dentry)
+ h_inode = h_dentry->d_inode;
+ }
hi_wh = au_hi_wh(inode, bcpup);
- if (!hi_wh)
+ if (!hi_wh && !h_inode)
err = au_sio_cpup_wh(dentry, bcpup, len, file);
else
/* already copied-up after unlink */
@@ -229,7 +235,7 @@ static int au_ready_to_write_wh(struct file *file, loff_t len,
int au_ready_to_write(struct file *file, loff_t len, struct au_pin *pin)
{
int err;
- aufs_bindex_t bstart, bcpup;
+ aufs_bindex_t bstart, bcpup, dbstart;
struct dentry *dentry, *parent, *h_dentry;
struct inode *h_inode, *inode;
struct super_block *sb;
@@ -246,7 +252,7 @@ int au_ready_to_write(struct file *file, loff_t len, struct au_pin *pin)
goto out;
}
- /* need to cpup */
+ /* need to cpup or reopen */
parent = dget_parent(dentry);
di_write_lock_parent(parent);
err = AuWbrCopyup(au_sbi(sb), dentry);
@@ -255,7 +261,7 @@ int au_ready_to_write(struct file *file, loff_t len, struct au_pin *pin)
goto out_dgrade;
err = 0;
- if (!au_h_dptr(parent, bcpup)) {
+ if (!d_unhashed(dentry) && !au_h_dptr(parent, bcpup)) {
err = au_cpup_dirs(dentry, bcpup);
if (unlikely(err))
goto out_dgrade;
@@ -268,25 +274,43 @@ int au_ready_to_write(struct file *file, loff_t len, struct au_pin *pin)
h_dentry = au_hf_top(file)->f_dentry;
h_inode = h_dentry->d_inode;
- mutex_lock_nested(&h_inode->i_mutex, AuLsc_I_CHILD);
- h_file = au_h_open_pre(dentry, bstart);
- if (IS_ERR(h_file)) {
- err = PTR_ERR(h_file);
- h_file = NULL;
- } else if (d_unhashed(dentry) /* || d_unhashed(h_dentry) */
- /* || !h_inode->i_nlink */) {
+ dbstart = au_dbstart(dentry);
+ if (dbstart <= bcpup) {
+ h_dentry = au_h_dptr(dentry, bcpup);
+ AuDebugOn(!h_dentry);
+ h_inode = h_dentry->d_inode;
+ AuDebugOn(!h_inode);
+ bstart = bcpup;
+ }
+
+ if (dbstart <= bcpup /* just reopen */
+ || !d_unhashed(dentry) /* copyup and reopen */
+ ) {
+ mutex_lock_nested(&h_inode->i_mutex, AuLsc_I_CHILD);
+ h_file = au_h_open_pre(dentry, bstart);
+ if (IS_ERR(h_file)) {
+ err = PTR_ERR(h_file);
+ h_file = NULL;
+ } else {
+ di_downgrade_lock(parent, AuLock_IR);
+ if (dbstart > bcpup)
+ err = au_sio_cpup_simple(dentry, bcpup, len,
+ AuCpup_DTIME);
+ if (!err)
+ err = au_reopen_nondir(file);
+ }
+ mutex_unlock(&h_inode->i_mutex);
+ au_h_open_post(dentry, bstart, h_file);
+ } else { /* copyup as wh and reopen */
+ /*
+ * since writable hfsplus branch is not supported,
+ * h_open_pre/post() are unnecessary.
+ */
+ mutex_lock_nested(&h_inode->i_mutex, AuLsc_I_CHILD);
err = au_ready_to_write_wh(file, len, bcpup);
di_downgrade_lock(parent, AuLock_IR);
- } else {
- di_downgrade_lock(parent, AuLock_IR);
- if (!au_h_dptr(dentry, bcpup))
- err = au_sio_cpup_simple(dentry, bcpup, len,
- AuCpup_DTIME);
- if (!err)
- err = au_reopen_nondir(file);
+ mutex_unlock(&h_inode->i_mutex);
}
- mutex_unlock(&h_inode->i_mutex);
- au_h_open_post(dentry, bstart, h_file);
if (!err) {
au_pin_set_parent_lflag(pin, /*lflag*/0);
@@ -351,7 +375,7 @@ static int au_file_refresh_by_inode(struct file *file, int *need_reopen)
sb = dentry->d_sb;
inode = dentry->d_inode;
bstart = au_ibstart(inode);
- if (bstart == finfo->fi_btop)
+ if (bstart == finfo->fi_btop || IS_ROOT(dentry))
goto out;
parent = dget_parent(dentry);
@@ -549,16 +573,13 @@ int au_reval_and_lock_fdi(struct file *file, int (*reopen)(struct file *file),
}
AuDbg("sigen %d, figen %d\n", sigen, figen);
- if (sigen != au_digen(dentry)
- || sigen != au_iigen(inode)) {
+ if (au_digen_test(dentry, sigen)) {
err = au_reval_dpath(dentry, sigen);
- if (unlikely(err < 0))
- goto out;
- AuDebugOn(au_digen(dentry) != sigen
- || au_iigen(inode) != sigen);
+ AuDebugOn(!err && au_digen_test(dentry, sigen));
}
- err = refresh_file(file, reopen);
+ if (!err)
+ err = refresh_file(file, reopen);
if (!err) {
if (!wlock) {
di_downgrade_lock(dentry, AuLock_IR);