/*
- * Copyright (C) 2005-2012 Junjiro R. Okajima
+ * Copyright (C) 2005-2013 Junjiro R. Okajima
*
* This program, aufs is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* handling file/dir, and address_space operation
*/
+#ifdef CONFIG_AUFS_DEBUG
+#include <linux/migrate.h>
+#endif
#include <linux/pagemap.h>
#include "aufs.h"
br = au_sbr(sb, bindex);
h_file = ERR_PTR(-EACCES);
exec_flag = flags & __FMODE_EXEC;
- if (exec_flag && (br->br_mnt->mnt_flags & MNT_NOEXEC))
+ if (exec_flag && (au_br_mnt(br)->mnt_flags & MNT_NOEXEC))
goto out;
/* drop flags for writing */
flags &= ~O_CREAT;
atomic_inc(&br->br_count);
h_path.dentry = h_dentry;
- h_path.mnt = br->br_mnt;
+ h_path.mnt = au_br_mnt(br);
if (!au_special_file(h_inode->i_mode))
h_file = vfsub_dentry_open(&h_path, flags);
else {
au_set_h_fptr(file, bstart, NULL);
}
AuDebugOn(au_fi(file)->fi_hdir);
- AuDebugOn(au_fbstart(file) < bstart);
+ /*
+ * it can happen
+ * file exists on both of rw and ro
+ * open --> dbstart and fbstart are both 0
+ * prepend a branch as rw, "rw" become ro
+ * remove rw/file
+ * delete the top branch, "rw" becomes rw again
+ * --> dbstart is 1, fbstart is still 0
+ * write --> fbstart is 0 but dbstart is 1
+ */
+ /* AuDebugOn(au_fbstart(file) < bstart); */
h_file = au_h_open(dentry, bstart, vfsub_file_flags(file) & ~O_TRUNC,
file);
err = PTR_ERR(h_file);
- if (IS_ERR(h_file))
+ if (IS_ERR(h_file)) {
+ if (h_file_tmp) {
+ atomic_inc(&au_sbr(dentry->d_sb, bstart)->br_count);
+ au_set_h_fptr(file, bstart, h_file_tmp);
+ h_file_tmp = NULL;
+ }
goto out; /* todo: close all? */
+ }
err = 0;
au_set_fbstart(file, bstart);
}
static int au_ready_to_write_wh(struct file *file, loff_t len,
- aufs_bindex_t bcpup)
+ aufs_bindex_t bcpup, struct au_pin *pin)
{
int err;
struct inode *inode, *h_inode;
- struct dentry *dentry, *h_dentry, *hi_wh;
-
- dentry = file->f_dentry;
- au_update_dbstart(dentry);
- inode = dentry->d_inode;
+ struct dentry *h_dentry, *hi_wh;
+ struct au_cp_generic cpg = {
+ .dentry = file->f_dentry,
+ .bdst = bcpup,
+ .bsrc = -1,
+ .len = len,
+ .pin = pin
+ };
+
+ au_update_dbstart(cpg.dentry);
+ inode = cpg.dentry->d_inode;
h_inode = NULL;
- if (au_dbstart(dentry) <= bcpup && au_dbend(dentry) >= bcpup) {
- h_dentry = au_h_dptr(dentry, bcpup);
+ if (au_dbstart(cpg.dentry) <= bcpup
+ && au_dbend(cpg.dentry) >= bcpup) {
+ h_dentry = au_h_dptr(cpg.dentry, bcpup);
if (h_dentry)
h_inode = h_dentry->d_inode;
}
hi_wh = au_hi_wh(inode, bcpup);
if (!hi_wh && !h_inode)
- err = au_sio_cpup_wh(dentry, bcpup, len, file);
+ err = au_sio_cpup_wh(&cpg, file);
else
/* already copied-up after unlink */
err = au_reopen_wh(file, bcpup, hi_wh);
if (!err
&& inode->i_nlink > 1
- && au_opt_test(au_mntflags(dentry->d_sb), PLINK))
- au_plink_append(inode, bcpup, au_h_dptr(dentry, bcpup));
+ && au_opt_test(au_mntflags(cpg.dentry->d_sb), PLINK))
+ au_plink_append(inode, bcpup, au_h_dptr(cpg.dentry, bcpup));
return err;
}
int au_ready_to_write(struct file *file, loff_t len, struct au_pin *pin)
{
int err;
- aufs_bindex_t bstart, bcpup, dbstart;
- struct dentry *dentry, *parent, *h_dentry;
- struct inode *h_inode, *inode;
+ aufs_bindex_t dbstart;
+ struct dentry *parent, *h_dentry;
+ struct inode *inode;
struct super_block *sb;
struct file *h_file;
-
- dentry = file->f_dentry;
- sb = dentry->d_sb;
- inode = dentry->d_inode;
+ struct au_cp_generic cpg = {
+ .dentry = file->f_dentry,
+ .bdst = -1,
+ .bsrc = -1,
+ .len = len,
+ .pin = pin,
+ .flags = AuCpup_DTIME
+ };
+
+ sb = cpg.dentry->d_sb;
+ inode = cpg.dentry->d_inode;
AuDebugOn(au_special_file(inode->i_mode));
- bstart = au_fbstart(file);
- err = au_test_ro(sb, bstart, inode);
+ cpg.bsrc = au_fbstart(file);
+ err = au_test_ro(sb, cpg.bsrc, inode);
if (!err && (au_hf_top(file)->f_mode & FMODE_WRITE)) {
- err = au_pin(pin, dentry, bstart, AuOpt_UDBA_NONE, /*flags*/0);
+ err = au_pin(pin, cpg.dentry, cpg.bsrc, AuOpt_UDBA_NONE,
+ /*flags*/0);
goto out;
}
/* need to cpup or reopen */
- parent = dget_parent(dentry);
+ parent = dget_parent(cpg.dentry);
di_write_lock_parent(parent);
- err = AuWbrCopyup(au_sbi(sb), dentry);
- bcpup = err;
+ err = AuWbrCopyup(au_sbi(sb), cpg.dentry);
+ cpg.bdst = err;
if (unlikely(err < 0))
goto out_dgrade;
err = 0;
- if (!d_unhashed(dentry) && !au_h_dptr(parent, bcpup)) {
- err = au_cpup_dirs(dentry, bcpup);
+ if (!d_unhashed(cpg.dentry) && !au_h_dptr(parent, cpg.bdst)) {
+ err = au_cpup_dirs(cpg.dentry, cpg.bdst);
if (unlikely(err))
goto out_dgrade;
}
- err = au_pin(pin, dentry, bcpup, AuOpt_UDBA_NONE,
+ err = au_pin(pin, cpg.dentry, cpg.bdst, AuOpt_UDBA_NONE,
AuPin_DI_LOCKED | AuPin_MNT_WRITE);
if (unlikely(err))
goto out_dgrade;
h_dentry = au_hf_top(file)->f_dentry;
- h_inode = h_dentry->d_inode;
- dbstart = au_dbstart(dentry);
- if (dbstart <= bcpup) {
- h_dentry = au_h_dptr(dentry, bcpup);
+ dbstart = au_dbstart(cpg.dentry);
+ if (dbstart <= cpg.bdst) {
+ h_dentry = au_h_dptr(cpg.dentry, cpg.bdst);
AuDebugOn(!h_dentry);
- h_inode = h_dentry->d_inode;
- AuDebugOn(!h_inode);
- bstart = bcpup;
+ cpg.bsrc = cpg.bdst;
}
- if (dbstart <= bcpup /* just reopen */
- || !d_unhashed(dentry) /* copyup and reopen */
+ if (dbstart <= cpg.bdst /* just reopen */
+ || !d_unhashed(cpg.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)) {
+ h_file = au_h_open_pre(cpg.dentry, cpg.bsrc);
+ if (IS_ERR(h_file))
err = PTR_ERR(h_file);
- h_file = NULL;
- } else {
+ else {
di_downgrade_lock(parent, AuLock_IR);
- if (dbstart > bcpup)
- err = au_sio_cpup_simple(dentry, bcpup, len,
- AuCpup_DTIME);
+ if (dbstart > cpg.bdst)
+ err = au_sio_cpup_simple(&cpg);
if (!err)
err = au_reopen_nondir(file);
+ au_h_open_post(cpg.dentry, cpg.bsrc, h_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);
+ err = au_ready_to_write_wh(file, len, cpg.bdst, pin);
di_downgrade_lock(parent, AuLock_IR);
- mutex_unlock(&h_inode->i_mutex);
}
if (!err) {
static int au_file_refresh_by_inode(struct file *file, int *need_reopen)
{
int err;
- aufs_bindex_t bstart;
struct au_pin pin;
struct au_finfo *finfo;
- struct dentry *dentry, *parent, *hi_wh;
+ struct dentry *parent, *hi_wh;
struct inode *inode;
struct super_block *sb;
+ struct au_cp_generic cpg = {
+ .dentry = file->f_dentry,
+ .bdst = -1,
+ .bsrc = -1,
+ .len = -1,
+ .pin = &pin,
+ .flags = AuCpup_DTIME
+ };
FiMustWriteLock(file);
err = 0;
finfo = au_fi(file);
- dentry = file->f_dentry;
- sb = dentry->d_sb;
- inode = dentry->d_inode;
- bstart = au_ibstart(inode);
- if (bstart == finfo->fi_btop || IS_ROOT(dentry))
+ sb = cpg.dentry->d_sb;
+ inode = cpg.dentry->d_inode;
+ cpg.bdst = au_ibstart(inode);
+ if (cpg.bdst == finfo->fi_btop || IS_ROOT(cpg.dentry))
goto out;
- parent = dget_parent(dentry);
- if (au_test_ro(sb, bstart, inode)) {
+ parent = dget_parent(cpg.dentry);
+ if (au_test_ro(sb, cpg.bdst, inode)) {
di_read_lock_parent(parent, !AuLock_IR);
- err = AuWbrCopyup(au_sbi(sb), dentry);
- bstart = err;
+ err = AuWbrCopyup(au_sbi(sb), cpg.dentry);
+ cpg.bdst = err;
di_read_unlock(parent, !AuLock_IR);
if (unlikely(err < 0))
goto out_parent;
}
di_read_lock_parent(parent, AuLock_IR);
- hi_wh = au_hi_wh(inode, bstart);
+ hi_wh = au_hi_wh(inode, cpg.bdst);
if (!S_ISDIR(inode->i_mode)
&& au_opt_test(au_mntflags(sb), PLINK)
&& au_plink_test(inode)
- && !d_unhashed(dentry)) {
- err = au_test_and_cpup_dirs(dentry, bstart);
+ && !d_unhashed(cpg.dentry)
+ && cpg.bdst < au_dbstart(cpg.dentry)) {
+ err = au_test_and_cpup_dirs(cpg.dentry, cpg.bdst);
if (unlikely(err))
goto out_unlock;
/* always superio. */
- err = au_pin(&pin, dentry, bstart, AuOpt_UDBA_NONE,
+ err = au_pin(&pin, cpg.dentry, cpg.bdst, AuOpt_UDBA_NONE,
AuPin_DI_LOCKED | AuPin_MNT_WRITE);
- if (!err)
- err = au_sio_cpup_simple(dentry, bstart, -1,
- AuCpup_DTIME);
- au_unpin(&pin);
+ if (!err) {
+ err = au_sio_cpup_simple(&cpg);
+ au_unpin(&pin);
+ }
} else if (hi_wh) {
/* already copied-up after unlink */
- err = au_reopen_wh(file, bstart, hi_wh);
+ err = au_reopen_wh(file, cpg.bdst, hi_wh);
*need_reopen = 0;
}
static int aufs_releasepage(struct page *page, gfp_t gfp)
{ AuUnsupport(); return 0; }
static int aufs_migratepage(struct address_space *mapping, struct page *newpage,
- struct page *page)
+ struct page *page, enum migrate_mode mode)
{ AuUnsupport(); return 0; }
static int aufs_launder_page(struct page *page)
{ AuUnsupport(); return 0; }