static ssize_t aufs_aio_write_sp(struct kiocb *kio, const struct iovec *iov, unsigned long nv, loff_t pos) { ssize_t err; aufs_bindex_t bstart; unsigned char wbr; struct super_block *sb; struct file *file, *h_file; file = kio->ki_filp; sb = file->f_dentry->d_sb; si_read_lock(sb, AuLock_FLUSH); fi_read_lock(file); bstart = au_fbstart(file); h_file = au_h_fptr(file, bstart); fi_read_unlock(file); wbr = !!au_br_writable(au_sbr(sb, bstart)->br_perm); si_read_unlock(sb); /* do not change the file in kio */ AuDebugOn(!h_file->f_op || !h_file->f_op->aio_write); err = h_file->f_op->aio_write(kio, iov, nv, pos); if (err > 0 && wbr) file_update_time(h_file); return err; }
static int aufs_release_sp(struct inode *inode, struct file *file) { int err; struct file *h_file; fi_read_lock(file); h_file = au_h_fptr(file, au_fbstart(file)); fi_read_unlock(file); /* close this fifo in aufs */ err = h_file->f_op->release(inode, file); /* ignore */ aufs_release_nondir(inode, file); /* ignore */ return err; }
int au_reopen_nondir(struct file *file) { int err; struct dentry *dentry; aufs_bindex_t bstart, bindex, bend; struct file *hidden_file, *h_file_tmp; dentry = file->f_dentry; LKTRTrace("%.*s\n", DLNPair(dentry)); DEBUG_ON(S_ISDIR(dentry->d_inode->i_mode) || !au_h_dptr(dentry)->d_inode); bstart = dbstart(dentry); h_file_tmp = NULL; if (fbstart(file) == bstart) { hidden_file = au_h_fptr(file); if (file->f_mode == hidden_file->f_mode) return 0; /* success */ h_file_tmp = hidden_file; get_file(h_file_tmp); set_h_fptr(file, bstart, NULL); } DEBUG_ON(fbstart(file) < bstart || ftofi(file)->fi_hfile[0 + bstart].hf_file); hidden_file = hidden_open(dentry, bstart, file->f_flags & ~O_TRUNC); //if (LktrCond) {fput(hidden_file); br_put(stobr(dentry->d_sb, bstart)); //hidden_file = ERR_PTR(-1);} err = PTR_ERR(hidden_file); if (IS_ERR(hidden_file)) goto out; // close all? err = 0; //cpup_file_flags(hidden_file, file); set_fbstart(file, bstart); set_h_fptr(file, bstart, hidden_file); memcpy(&hidden_file->f_ra, &file->f_ra, sizeof(file->f_ra)); //?? /* close lower files */ bend = fbend(file); for (bindex = bstart + 1; bindex <= bend; bindex++) set_h_fptr(file, bindex, NULL); set_fbend(file, bstart); out: if (h_file_tmp) fput(h_file_tmp); TraceErr(err); return err; }
int au_reopen_nondir(struct file *file) { int err; aufs_bindex_t bstart, bindex, bend; struct dentry *dentry; struct file *h_file, *h_file_tmp; dentry = file->f_dentry; AuDebugOn(au_special_file(dentry->d_inode->i_mode)); bstart = au_dbstart(dentry); h_file_tmp = NULL; if (au_fbstart(file) == bstart) { h_file = au_h_fptr(file, bstart); if (file->f_mode == h_file->f_mode) return 0; /* success */ h_file_tmp = h_file; get_file(h_file_tmp); au_set_h_fptr(file, bstart, NULL); } AuDebugOn(au_fbstart(file) < bstart || au_fi(file)->fi_hfile[0 + bstart].hf_file); h_file = au_h_open(dentry, bstart, vfsub_file_flags(file) & ~O_TRUNC, file); err = PTR_ERR(h_file); if (IS_ERR(h_file)) goto out; /* todo: close all? */ err = 0; au_set_fbstart(file, bstart); au_set_h_fptr(file, bstart, h_file); au_update_figen(file); /* todo: necessary? */ /* file->f_ra = h_file->f_ra; */ /* close lower files */ bend = au_fbend(file); for (bindex = bstart + 1; bindex <= bend; bindex++) au_set_h_fptr(file, bindex, NULL); au_set_fbend(file, bstart); out: if (h_file_tmp) fput(h_file_tmp); return err; }
/* * prepare the @file for writing. */ int au_ready_to_write(struct file *file, loff_t len) { int err; struct dentry *dentry, *parent, *hidden_dentry, *hidden_parent; struct inode *hidden_inode, *hidden_dir, *inode, *dir; struct super_block *sb; aufs_bindex_t bstart, bcpup; dentry = file->f_dentry; LKTRTrace("%.*s, len %Ld\n", DLNPair(dentry), len); FiMustWriteLock(file); sb = dentry->d_sb; bstart = fbstart(file); DEBUG_ON(ftobr(file, bstart) != stobr(sb, bstart)); inode = dentry->d_inode; ii_read_lock_child(inode); LKTRTrace("rdonly %d, bstart %d\n", test_ro(sb, bstart, inode), bstart); err = test_ro(sb, bstart, inode); ii_read_unlock(inode); if (!err && (au_h_fptr(file)->f_mode & FMODE_WRITE)) return 0; /* need to cpup */ parent = dentry->d_parent; // dget_parent() di_write_lock_child(dentry); di_write_lock_parent(parent); bcpup = err = find_rw_parent_br(dentry, bstart); //bcpup = err = find_rw_br(sb, bstart); if (unlikely(err < 0)) goto out_unlock; err = 0; hidden_parent = au_h_dptr_i(parent, bcpup); if (!hidden_parent) { err = cpup_dirs(dentry, bcpup, NULL); //if (LktrCond) err = -1; if (unlikely(err)) goto out_unlock; hidden_parent = au_h_dptr_i(parent, bcpup); } hidden_dir = hidden_parent->d_inode; hidden_dentry = au_h_fptr(file)->f_dentry; hidden_inode = hidden_dentry->d_inode; dir = parent->d_inode; hdir_lock(hidden_dir, dir, bcpup); hi_lock_child(hidden_inode); if (d_unhashed(dentry) || d_unhashed(hidden_dentry) /* || !hidden_inode->i_nlink */) { if (!au_test_perm(hidden_dir, MAY_EXEC | MAY_WRITE, need_dlgt(sb))) err = cpup_wh_file(file, bcpup, len); else { struct cpup_wh_file_args args = { .errp = &err, .file = file, .bdst = bcpup, .len = len }; au_wkq_wait(call_cpup_wh_file, &args, /*dlgt*/0); } //if (LktrCond) err = -1; TraceErr(err); } else { if (!au_h_dptr_i(dentry, bcpup))
/* * 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; }