int au_refresh_hinode(struct inode *inode, struct dentry *dentry) { int err, e, update; unsigned int flags; umode_t mode; aufs_bindex_t bindex, bend; unsigned char isdir; struct au_hinode *p; struct au_iinfo *iinfo; err = au_ii_refresh(inode, &update); if (unlikely(err)) goto out; update = 0; iinfo = au_ii(inode); p = iinfo->ii_hinode + iinfo->ii_bstart; mode = (inode->i_mode & S_IFMT); isdir = S_ISDIR(mode); flags = au_hi_flags(inode, isdir); bend = au_dbend(dentry); for (bindex = au_dbstart(dentry); bindex <= bend; bindex++) { struct inode *h_i; struct dentry *h_d; h_d = au_h_dptr(dentry, bindex); if (!h_d || !h_d->d_inode) continue; AuDebugOn(mode != (h_d->d_inode->i_mode & S_IFMT)); if (iinfo->ii_bstart <= bindex && bindex <= iinfo->ii_bend) { h_i = au_h_iptr(inode, bindex); if (h_i) { if (h_i == h_d->d_inode) continue; err = -EIO; break; } } if (bindex < iinfo->ii_bstart) iinfo->ii_bstart = bindex; if (iinfo->ii_bend < bindex) iinfo->ii_bend = bindex; au_set_h_iptr(inode, bindex, au_igrab(h_d->d_inode), flags); update = 1; } au_update_ibrange(inode, /*do_put_zero*/0); e = au_dy_irefresh(inode); if (unlikely(e && !err)) err = e; if (!err) au_refresh_hinode_attr(inode, update && isdir); out: AuTraceErr(err); return err; }
int au_refresh_hinode(struct inode *inode, struct dentry *dentry) { int err, update; unsigned int flags; aufs_bindex_t bindex, bend; unsigned char isdir; struct inode *first; struct au_hinode *p; struct au_iinfo *iinfo; err = au_refresh_hinode_self(inode, /*do_attr*/0); if (unlikely(err)) goto out; update = 0; iinfo = au_ii(inode); p = iinfo->ii_hinode + iinfo->ii_bstart; first = p->hi_inode; isdir = S_ISDIR(inode->i_mode); flags = au_hi_flags(inode, isdir); bend = au_dbend(dentry); for (bindex = au_dbstart(dentry); bindex <= bend; bindex++) { struct inode *h_i; struct dentry *h_d; h_d = au_h_dptr(dentry, bindex); if (!h_d || !h_d->d_inode) continue; if (iinfo->ii_bstart <= bindex && bindex <= iinfo->ii_bend) { h_i = au_h_iptr(inode, bindex); if (h_i) { if (h_i == h_d->d_inode) continue; err = -EIO; break; } } if (bindex < iinfo->ii_bstart) iinfo->ii_bstart = bindex; if (iinfo->ii_bend < bindex) iinfo->ii_bend = bindex; au_set_h_iptr(inode, bindex, au_igrab(h_d->d_inode), flags); update = 1; } au_update_brange(inode, /*do_put_zero*/0); if (unlikely(err)) goto out; au_refresh_hinode_attr(inode, update && isdir); out: return err; }
static int set_inode(struct inode *inode, struct dentry *dentry) { int err; unsigned int flags; umode_t mode; aufs_bindex_t bindex, bstart, btail; unsigned char isdir; struct dentry *h_dentry; struct inode *h_inode; struct au_iinfo *iinfo; IiMustWriteLock(inode); err = 0; isdir = 0; bstart = au_dbstart(dentry); h_inode = au_h_dptr(dentry, bstart)->d_inode; mode = h_inode->i_mode; switch (mode & S_IFMT) { case S_IFREG: btail = au_dbtail(dentry); inode->i_op = &aufs_iop; inode->i_fop = &aufs_file_fop; inode->i_mapping->a_ops = &aufs_aop; break; case S_IFDIR: isdir = 1; btail = au_dbtaildir(dentry); inode->i_op = &aufs_dir_iop; inode->i_fop = &aufs_dir_fop; break; case S_IFLNK: btail = au_dbtail(dentry); inode->i_op = &aufs_symlink_iop; break; case S_IFBLK: case S_IFCHR: case S_IFIFO: case S_IFSOCK: btail = au_dbtail(dentry); inode->i_op = &aufs_iop; au_init_special_fop(inode, mode, h_inode->i_rdev); break; default: AuIOErr("Unknown file type 0%o\n", mode); err = -EIO; goto out; } /* do not set inotify for whiteouted dirs (SHWH mode) */ flags = au_hi_flags(inode, isdir); if (au_opt_test(au_mntflags(dentry->d_sb), SHWH) && au_ftest_hi(flags, HINOTIFY) && dentry->d_name.len > AUFS_WH_PFX_LEN && !memcmp(dentry->d_name.name, AUFS_WH_PFX, AUFS_WH_PFX_LEN)) au_fclr_hi(flags, HINOTIFY); iinfo = au_ii(inode); iinfo->ii_bstart = bstart; iinfo->ii_bend = btail; for (bindex = bstart; bindex <= btail; bindex++) { h_dentry = au_h_dptr(dentry, bindex); if (h_dentry) au_set_h_iptr(inode, bindex, au_igrab(h_dentry->d_inode), flags); } au_cpup_attr_all(inode, /*force*/1); out: return err; }
int au_opts_mount(struct super_block *sb, struct au_opts *opts) { int err; unsigned int tmp; aufs_bindex_t bindex, bend; struct au_opt *opt; struct au_opt_xino *opt_xino, xino; struct au_sbinfo *sbinfo; struct au_branch *br; SiMustWriteLock(sb); err = 0; opt_xino = NULL; opt = opts->opt; while (err >= 0 && opt->type != Opt_tail) err = au_opt_simple(sb, opt++, opts); if (err > 0) err = 0; else if (unlikely(err < 0)) goto out; /* disable xino and udba temporary */ sbinfo = au_sbi(sb); tmp = sbinfo->si_mntflags; au_opt_clr(sbinfo->si_mntflags, XINO); au_opt_set_udba(sbinfo->si_mntflags, UDBA_REVAL); opt = opts->opt; while (err >= 0 && opt->type != Opt_tail) err = au_opt_br(sb, opt++, opts); if (err > 0) err = 0; else if (unlikely(err < 0)) goto out; bend = au_sbend(sb); if (unlikely(bend < 0)) { err = -EINVAL; pr_err("no branches\n"); goto out; } if (au_opt_test(tmp, XINO)) au_opt_set(sbinfo->si_mntflags, XINO); opt = opts->opt; while (!err && opt->type != Opt_tail) err = au_opt_xino(sb, opt++, &opt_xino, opts); if (unlikely(err)) goto out; err = au_opts_verify(sb, sb->s_flags, tmp); if (unlikely(err)) goto out; /* restore xino */ if (au_opt_test(tmp, XINO) && !opt_xino) { xino.file = au_xino_def(sb); err = PTR_ERR(xino.file); if (IS_ERR(xino.file)) goto out; err = au_xino_set(sb, &xino, /*remount*/0); fput(xino.file); if (unlikely(err)) goto out; } /* restore udba */ tmp &= AuOptMask_UDBA; sbinfo->si_mntflags &= ~AuOptMask_UDBA; sbinfo->si_mntflags |= tmp; bend = au_sbend(sb); for (bindex = 0; bindex <= bend; bindex++) { br = au_sbr(sb, bindex); err = au_hnotify_reset_br(tmp, br, br->br_perm); if (unlikely(err)) AuIOErr("hnotify failed on br %d, %d, ignored\n", bindex, err); /* go on even if err */ } if (au_opt_test(tmp, UDBA_HNOTIFY)) { struct inode *dir = sb->s_root->d_inode; au_hn_reset(dir, au_hi_flags(dir, /*isdir*/1) & ~AuHi_XINO); } out: return err; }
static int au_cpdown_dir(struct dentry *dentry, aufs_bindex_t bdst, struct dentry *h_parent, void *arg) { int err, rerr; aufs_bindex_t bopq, bstart; struct path h_path; struct dentry *parent; struct inode *h_dir, *h_inode, *inode, *dir; struct au_cpdown_dir_args *args = arg; bstart = au_dbstart(dentry); /* dentry is di-locked */ parent = dget_parent(dentry); dir = parent->d_inode; h_dir = h_parent->d_inode; AuDebugOn(h_dir != au_h_iptr(dir, bdst)); IMustLock(h_dir); err = au_lkup_neg(dentry, bdst); if (unlikely(err < 0)) goto out; h_path.dentry = au_h_dptr(dentry, bdst); h_path.mnt = au_sbr_mnt(dentry->d_sb, bdst); err = vfsub_sio_mkdir(au_h_iptr(dir, bdst), &h_path, S_IRWXU | S_IRUGO | S_IXUGO); if (unlikely(err)) goto out_put; au_fset_cpdown(args->flags, MADE_DIR); bopq = au_dbdiropq(dentry); au_fclr_cpdown(args->flags, WHED); au_fclr_cpdown(args->flags, DIROPQ); if (au_dbwh(dentry) == bdst) au_fset_cpdown(args->flags, WHED); if (!au_ftest_cpdown(args->flags, PARENT_OPQ) && bopq <= bdst) au_fset_cpdown(args->flags, PARENT_OPQ); h_inode = h_path.dentry->d_inode; mutex_lock_nested(&h_inode->i_mutex, AuLsc_I_CHILD); if (au_ftest_cpdown(args->flags, WHED)) { err = au_cpdown_dir_opq(dentry, bdst, args); if (unlikely(err)) { mutex_unlock(&h_inode->i_mutex); goto out_dir; } } err = au_cpdown_attr(&h_path, au_h_dptr(dentry, bstart)); mutex_unlock(&h_inode->i_mutex); if (unlikely(err)) goto out_opq; if (au_ftest_cpdown(args->flags, WHED)) { err = au_cpdown_dir_wh(dentry, h_parent, dir, bdst); if (unlikely(err)) goto out_opq; } inode = dentry->d_inode; if (au_ibend(inode) < bdst) au_set_ibend(inode, bdst); au_set_h_iptr(inode, bdst, au_igrab(h_inode), au_hi_flags(inode, /*isdir*/1)); goto out; /* success */ /* revert */ out_opq: if (au_ftest_cpdown(args->flags, DIROPQ)) { mutex_lock_nested(&h_inode->i_mutex, AuLsc_I_CHILD); rerr = au_diropq_remove(dentry, bdst); mutex_unlock(&h_inode->i_mutex); if (unlikely(rerr)) { AuIOErr("failed removing diropq for %.*s b%d (%d)\n", AuDLNPair(dentry), bdst, rerr); err = -EIO; goto out; } } out_dir: if (au_ftest_cpdown(args->flags, MADE_DIR)) { rerr = vfsub_sio_rmdir(au_h_iptr(dir, bdst), &h_path); if (unlikely(rerr)) { AuIOErr("failed removing %.*s b%d (%d)\n", AuDLNPair(dentry), bdst, rerr); err = -EIO; } } out_put: au_set_h_dptr(dentry, bdst, NULL); if (au_dbend(dentry) == bdst) au_update_dbend(dentry); out: dput(parent); return err; }