static struct dentry * lock_hdir_create_wh(struct dentry *dentry, int isdir, aufs_bindex_t *bcpup, struct dtime *dt) { struct dentry *wh_dentry; int err, need_wh; struct dentry *hidden_parent, *parent; struct inode *dir, *h_dir; struct lkup_args lkup; LKTRTrace("%.*s, isdir %d\n", DLNPair(dentry), isdir); err = need_wh = wr_dir_need_wh(dentry, isdir, bcpup, NULL); //err = -1; wh_dentry = ERR_PTR(err); if (unlikely(err < 0)) goto out; parent = dentry->d_parent; dir = parent->d_inode; hidden_parent = au_h_dptr_i(parent, *bcpup); h_dir = hidden_parent->d_inode; hdir_lock(h_dir, dir, *bcpup); dtime_store(dt, parent, hidden_parent); if (!need_wh) return NULL; /* success, no need to create whiteout */ lkup.nfsmnt = au_nfsmnt(dentry->d_sb, *bcpup); lkup.dlgt = need_dlgt(dentry->d_sb); wh_dentry = simple_create_wh(dentry, *bcpup, hidden_parent, &lkup); //wh_dentry = ERR_PTR(-1); if (!IS_ERR(wh_dentry)) goto out; /* success */ /* returns with the parent is locked and wh_dentry is DGETed */ hdir_unlock(h_dir, dir, *bcpup); out: TraceErrPtr(wh_dentry); return wh_dentry; }
/* * final procedure of adding a new entry, except link(2). * remove whiteout, instantiate, copyup the parent dir's times and size * and update version. * if it failed, re-create the removed whiteout. */ static int epilog(struct inode *dir, aufs_bindex_t bindex, struct dentry *wh_dentry, struct dentry *dentry) { int err, rerr; aufs_bindex_t bwh; struct inode *inode, *h_dir; struct dentry *wh; struct au_ndx ndx; struct super_block *sb; LKTRTrace("wh %p, %.*s\n", wh_dentry, AuDLNPair(dentry)); sb = dentry->d_sb; bwh = -1; if (wh_dentry) { h_dir = wh_dentry->d_parent->d_inode; /* dir inode is locked */ IMustLock(h_dir); AuDebugOn(au_h_iptr(dir, bindex) != h_dir); bwh = au_dbwh(dentry); err = au_wh_unlink_dentry(au_hi(dir, bindex), wh_dentry, dentry, /*dlgt*/0); if (unlikely(err)) goto out; } inode = au_new_inode(dentry, /*must_new*/1); if (!IS_ERR(inode)) { d_instantiate(dentry, inode); dir = dentry->d_parent->d_inode; /* dir inode is locked */ IMustLock(dir); /* or always cpup dir mtime? */ if (au_ibstart(dir) == au_dbstart(dentry)) au_cpup_attr_timesizes(dir); dir->i_version++; return 0; /* success */ } err = PTR_ERR(inode); if (!wh_dentry) goto out; /* revert */ ndx.flags = 0; if (au_test_dlgt(au_mntflags(sb))) au_fset_ndx(ndx.flags, DLGT); ndx.nfsmnt = au_nfsmnt(sb, bwh); ndx.nd = NULL; /* ndx.br = NULL; */ /* dir inode is locked */ wh = au_wh_create(dentry, bwh, wh_dentry->d_parent, &ndx); rerr = PTR_ERR(wh); if (IS_ERR(wh)) { AuIOErr("%.*s reverting whiteout failed(%d, %d)\n", AuDLNPair(dentry), err, rerr); err = -EIO; } else dput(wh); out: AuTraceErr(err); return err; }
/* * initial procedure of adding a new entry. * prepare writable branch and the parent dir, lock it, * lookup whiteout for the new entry. */ static struct dentry* lock_hdir_lkup_wh(struct dentry *dentry, struct au_dtime *dt, struct dentry *src_dentry, struct au_pin *pin, struct au_wr_dir_args *wr_dir_args) { struct dentry *wh_dentry, *h_parent; struct super_block *sb; int err; unsigned int mnt_flags; unsigned char pin_flags; aufs_bindex_t bstart, bcpup; struct au_ndx ndx; LKTRTrace("%.*s, src %p\n", AuDLNPair(dentry), src_dentry); bstart = au_dbstart(dentry); err = au_wr_dir(dentry, src_dentry, wr_dir_args); bcpup = err; wh_dentry = ERR_PTR(err); if (unlikely(err < 0)) goto out; sb = dentry->d_sb; mnt_flags = au_mntflags(sb); pin_flags = AuPin_DI_LOCKED | AuPin_MNT_WRITE; if (dt && au_opt_test(mnt_flags, UDBA_INOTIFY)) au_fset_pin(pin_flags, DO_GPARENT); err = au_pin(pin, dentry, bcpup, pin_flags); wh_dentry = ERR_PTR(err); if (unlikely(err)) goto out; ndx.nfsmnt = au_nfsmnt(sb, bcpup); ndx.flags = 0; if (au_test_dlgt(mnt_flags)) au_fset_ndx(ndx.flags, DLGT); ndx.nd = NULL; /* ndx.br = NULL; */ /* ndx.nd_file = NULL; */ h_parent = au_pinned_h_parent(pin); if (!au_opt_test(mnt_flags, UDBA_NONE) && au_dbstart(dentry) == bcpup) { struct nameidata nd; if (ndx.nfsmnt) { /* todo: dirty? */ ndx.nd = &nd; ndx.br = au_sbr(sb, bcpup); memset(&nd, 0, sizeof(nd)); nd.flags = LOOKUP_CREATE; nd.intent.open.flags = O_EXCL; } err = au_may_add(dentry, bcpup, h_parent, au_ftest_wrdir(wr_dir_args->flags, ISDIR), &ndx); wh_dentry = ERR_PTR(err); if (unlikely(err)) goto out_unpin; ndx.nd = NULL; ndx.br = NULL; } if (dt) au_dtime_store(dt, au_pinned_parent(pin), h_parent, au_pinned_hdir(pin), au_pinned_hgdir(pin)); wh_dentry = NULL; if (/* bcpup != bstart || */ bcpup != au_dbwh(dentry)) goto out; /* success */ wh_dentry = au_wh_lkup(h_parent, &dentry->d_name, &ndx); out_unpin: if (IS_ERR(wh_dentry)) au_unpin(pin); out: AuTraceErrPtr(wh_dentry); return wh_dentry; }
/* * 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; }