static int au_reopen_wh(struct file *file, aufs_bindex_t btgt, struct dentry *hi_wh) { int err; aufs_bindex_t bstart; struct au_dinfo *dinfo; struct dentry *h_dentry; dinfo = au_di(file->f_dentry); AuRwMustWriteLock(&dinfo->di_rwsem); bstart = dinfo->di_bstart; dinfo->di_bstart = btgt; h_dentry = dinfo->di_hdentry[0 + btgt].hd_dentry; dinfo->di_hdentry[0 + btgt].hd_dentry = hi_wh; err = au_reopen_nondir(file); dinfo->di_hdentry[0 + btgt].hd_dentry = h_dentry; dinfo->di_bstart = bstart; return err; }
/* * prepare the @file for writing. */ 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; struct super_block *sb; struct file *h_file; dentry = file->f_dentry; sb = dentry->d_sb; inode = dentry->d_inode; AuDebugOn(au_special_file(inode->i_mode)); bstart = au_fbstart(file); err = au_test_ro(sb, bstart, inode); if (!err && (au_hf_top(file)->f_mode & FMODE_WRITE)) { err = au_pin(pin, dentry, bstart, AuOpt_UDBA_NONE, /*flags*/0); goto out; } /* need to cpup or reopen */ parent = dget_parent(dentry); di_write_lock_parent(parent); err = AuWbrCopyup(au_sbi(sb), dentry); bcpup = 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 (unlikely(err)) goto out_dgrade; } err = au_pin(pin, dentry, bcpup, 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); 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); mutex_unlock(&h_inode->i_mutex); } if (!err) { au_pin_set_parent_lflag(pin, /*lflag*/0); goto out_dput; /* success */ } au_unpin(pin); goto out_unlock; out_dgrade: di_downgrade_lock(parent, AuLock_IR); out_unlock: di_read_unlock(parent, AuLock_IR); out_dput: dput(parent); out: return err; }
/* * copyup the deleted file for writing. */ static int cpup_wh_file(struct file *file, aufs_bindex_t bdst, loff_t len) { int err; struct dentry *dentry, *parent, *hidden_parent, *tmp_dentry; struct dentry *hidden_dentry_bstart, *hidden_dentry_bdst; struct inode *hidden_dir; aufs_bindex_t bstart; struct aufs_dinfo *dinfo; struct dtime dt; struct lkup_args lkup; struct super_block *sb; dentry = file->f_dentry; LKTRTrace("%.*s, bdst %d, len %Lu\n", DLNPair(dentry), bdst, len); DEBUG_ON(S_ISDIR(dentry->d_inode->i_mode) || !(file->f_mode & FMODE_WRITE)); DiMustWriteLock(dentry); parent = dentry->d_parent; IiMustAnyLock(parent->d_inode); hidden_parent = au_h_dptr_i(parent, bdst); DEBUG_ON(!hidden_parent); hidden_dir = hidden_parent->d_inode; DEBUG_ON(!hidden_dir); IMustLock(hidden_dir); sb = parent->d_sb; lkup.nfsmnt = au_nfsmnt(sb, bdst); lkup.dlgt = need_dlgt(sb); tmp_dentry = lkup_whtmp(hidden_parent, &dentry->d_name, &lkup); //if (LktrCond) {dput(tmp_dentry); tmp_dentry = ERR_PTR(-1);} err = PTR_ERR(tmp_dentry); if (IS_ERR(tmp_dentry)) goto out; dtime_store(&dt, parent, hidden_parent); dinfo = dtodi(dentry); bstart = dinfo->di_bstart; hidden_dentry_bdst = dinfo->di_hdentry[0 + bdst].hd_dentry; hidden_dentry_bstart = dinfo->di_hdentry[0 + bstart].hd_dentry; dinfo->di_bstart = bdst; dinfo->di_hdentry[0 + bdst].hd_dentry = tmp_dentry; dinfo->di_hdentry[0 + bstart].hd_dentry = au_h_fptr(file)->f_dentry; err = cpup_single(dentry, bdst, bstart, len, au_flags_cpup(!CPUP_DTIME, parent)); //if (LktrCond) err = -1; if (!err) err = au_reopen_nondir(file); //err = -1; if (unlikely(err)) { dinfo->di_hdentry[0 + bstart].hd_dentry = hidden_dentry_bstart; dinfo->di_hdentry[0 + bdst].hd_dentry = hidden_dentry_bdst; dinfo->di_bstart = bstart; goto out_tmp; } DEBUG_ON(!d_unhashed(dentry)); err = vfsub_unlink(hidden_dir, tmp_dentry, lkup.dlgt); //if (LktrCond) err = -1; if (unlikely(err)) { IOErr("failed remove copied-up tmp file %.*s(%d)\n", DLNPair(tmp_dentry), err); err = -EIO; } dtime_revert(&dt, !CPUP_LOCKED_GHDIR); out_tmp: dput(tmp_dentry); out: TraceErr(err); return err; }
/* * prepare the @file for writing. */ int au_ready_to_write(struct file *file, loff_t len, struct au_pin *pin) { int err; aufs_bindex_t bstart, bcpup; struct dentry *dentry, *parent, *h_dentry; struct inode *h_inode, *inode; struct super_block *sb; dentry = file->f_dentry; sb = dentry->d_sb; inode = dentry->d_inode; AuDebugOn(au_special_file(inode->i_mode)); bstart = au_fbstart(file); err = au_test_ro(sb, bstart, inode); if (!err && (au_h_fptr(file, bstart)->f_mode & FMODE_WRITE)) { err = au_pin(pin, dentry, bstart, AuOpt_UDBA_NONE, /*flags*/0); goto out; } /* need to cpup */ parent = dget_parent(dentry); di_write_lock_parent(parent); err = AuWbrCopyup(au_sbi(sb), dentry); bcpup = err; if (unlikely(err < 0)) goto out_dgrade; err = 0; if (!au_h_dptr(parent, bcpup)) { err = au_cpup_dirs(dentry, bcpup); if (unlikely(err)) goto out_dgrade; } err = au_pin(pin, dentry, bcpup, AuOpt_UDBA_NONE, AuPin_DI_LOCKED | AuPin_MNT_WRITE); if (unlikely(err)) goto out_dgrade; h_dentry = au_h_fptr(file, bstart)->f_dentry; h_inode = h_dentry->d_inode; mutex_lock_nested(&h_inode->i_mutex, AuLsc_I_CHILD); if (d_unhashed(dentry) /* || d_unhashed(h_dentry) */ /* || !h_inode->i_nlink */) { 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); if (!err) { au_pin_set_parent_lflag(pin, /*lflag*/0); goto out_dput; /* success */ } au_unpin(pin); goto out_unlock; out_dgrade: di_downgrade_lock(parent, AuLock_IR); out_unlock: di_read_unlock(parent, AuLock_IR); out_dput: dput(parent); out: return err; }
static int au_ready_to_write_wh(struct file *file, loff_t len, aufs_bindex_t bcpup, struct au_pin *pin) { int err; struct inode *inode, *h_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(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(&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(cpg.dentry->d_sb), PLINK)) au_plink_append(inode, bcpup, au_h_dptr(cpg.dentry, bcpup)); return err; } /* * prepare the @file for writing. */ int au_ready_to_write(struct file *file, loff_t len, struct au_pin *pin) { int err; aufs_bindex_t dbstart; struct dentry *parent, *h_dentry; struct inode *inode; struct super_block *sb; struct file *h_file; 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)); 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, cpg.dentry, cpg.bsrc, AuOpt_UDBA_NONE, /*flags*/0); goto out; } /* need to cpup or reopen */ parent = dget_parent(cpg.dentry); di_write_lock_parent(parent); err = AuWbrCopyup(au_sbi(sb), cpg.dentry); cpg.bdst = err; if (unlikely(err < 0)) goto out_dgrade; err = 0; 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, 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; dbstart = au_dbstart(cpg.dentry); if (dbstart <= cpg.bdst) { h_dentry = au_h_dptr(cpg.dentry, cpg.bdst); AuDebugOn(!h_dentry); cpg.bsrc = cpg.bdst; } if (dbstart <= cpg.bdst /* just reopen */ || !d_unhashed(cpg.dentry) /* copyup and reopen */ ) { h_file = au_h_open_pre(cpg.dentry, cpg.bsrc, /*force_wr*/0); if (IS_ERR(h_file)) err = PTR_ERR(h_file); else { di_downgrade_lock(parent, AuLock_IR); 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); } } else { /* copyup as wh and reopen */ /* * since writable hfsplus branch is not supported, * h_open_pre/post() are unnecessary. */ err = au_ready_to_write_wh(file, len, cpg.bdst, pin); di_downgrade_lock(parent, AuLock_IR); } if (!err) { au_pin_set_parent_lflag(pin, /*lflag*/0); goto out_dput; /* success */ } au_unpin(pin); goto out_unlock; out_dgrade: di_downgrade_lock(parent, AuLock_IR); out_unlock: di_read_unlock(parent, AuLock_IR); out_dput: dput(parent); out: return err; } /* ---------------------------------------------------------------------- */ int au_do_flush(struct file *file, fl_owner_t id, int (*flush)(struct file *file, fl_owner_t id)) { int err; struct super_block *sb; struct inode *inode; inode = file_inode(file); sb = inode->i_sb; si_noflush_read_lock(sb); fi_read_lock(file); ii_read_lock_child(inode); err = flush(file, id); au_cpup_attr_timesizes(inode); ii_read_unlock(inode); fi_read_unlock(file); si_read_unlock(sb); return err; }