static void au_refresh_hinode_attr(struct inode *inode, int do_version) { au_cpup_attr_all(inode, /*force*/0); au_update_iigen(inode); if (do_version) inode->i_version++; }
int aufs_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *st) { int err; aufs_bindex_t bindex; struct inode *inode; struct dentry *h_dentry; struct super_block *sb; unsigned int mnt_flags; LKTRTrace("%.*s\n", AuDLNPair(dentry)); inode = dentry->d_inode; sb = dentry->d_sb; aufs_read_lock(dentry, AuLock_FLUSH | AuLock_IR); /* todo: refine it */ mnt_flags = au_mntflags(sb); if (au_opt_test(mnt_flags, PLINK) && au_plink_test(sb, inode)) goto plinked; h_dentry = au_h_dget_any(dentry, &bindex); err = PTR_ERR(h_dentry); if (IS_ERR(h_dentry)) goto out; err = -ENOENT; if (h_dentry->d_inode) err = vfsub_getattr(au_sbr_mnt(sb, bindex), h_dentry, st, au_test_dlgt(mnt_flags)); dput(h_dentry); if (!err) { au_cpup_attr_all(inode); plinked: generic_fillattr(inode, st); } out: aufs_read_unlock(dentry, AuLock_IR); AuTraceErr(err); 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_br_del(struct super_block *sb, struct au_opt_del *del, int remount) { int err, rerr, i; unsigned int mnt_flags; aufs_bindex_t bindex, bend, br_id; unsigned char do_wh, verbose; struct au_branch *br; struct au_wbr *wbr; err = 0; bindex = au_find_dbindex(sb->s_root, del->h_path.dentry); if (bindex < 0) { if (remount) goto out; /* success */ err = -ENOENT; pr_err("%s no such branch\n", del->pathname); goto out; } AuDbg("bindex b%d\n", bindex); err = -EBUSY; mnt_flags = au_mntflags(sb); verbose = !!au_opt_test(mnt_flags, VERBOSE); bend = au_sbend(sb); if (unlikely(!bend)) { AuVerbose(verbose, "no more branches left\n"); goto out; } br = au_sbr(sb, bindex); i = atomic_read(&br->br_count); if (unlikely(i)) { AuVerbose(verbose, "%d file(s) opened\n", i); goto out; } wbr = br->br_wbr; do_wh = wbr && (wbr->wbr_whbase || wbr->wbr_plink || wbr->wbr_orph); if (do_wh) { /* instead of WbrWhMustWriteLock(wbr) */ SiMustWriteLock(sb); for (i = 0; i < AuBrWh_Last; i++) { dput(wbr->wbr_wh[i]); wbr->wbr_wh[i] = NULL; } } err = test_children_busy(sb->s_root, bindex, verbose); if (unlikely(err)) { if (do_wh) goto out_wh; goto out; } err = 0; br_id = br->br_id; if (!remount) au_br_do_del(sb, bindex, br); else { sysaufs_brs_del(sb, bindex); au_br_do_del(sb, bindex, br); sysaufs_brs_add(sb, bindex); } if (!bindex) { au_cpup_attr_all(sb->s_root->d_inode, /*force*/1); sb->s_maxbytes = au_sbr_sb(sb, 0)->s_maxbytes; } else au_sub_nlink(sb->s_root->d_inode, del->h_path.dentry->d_inode); if (au_opt_test(mnt_flags, PLINK)) au_plink_half_refresh(sb, br_id); if (au_xino_brid(sb) == br_id) au_xino_brid_set(sb, -1); goto out; /* success */ out_wh: /* revert */ rerr = au_br_init_wh(sb, br, br->br_perm, del->h_path.dentry); if (rerr) pr_warning("failed re-creating base whiteout, %s. (%d)\n", del->pathname, rerr); out: return err; }
int au_br_add(struct super_block *sb, struct au_opt_add *add, int remount) { int err; aufs_bindex_t bend, add_bindex; struct dentry *root, *h_dentry; struct inode *root_inode; struct au_branch *add_branch; root = sb->s_root; root_inode = root->d_inode; IMustLock(root_inode); err = test_add(sb, add, remount); if (unlikely(err < 0)) goto out; if (err) { err = 0; goto out; /* success */ } bend = au_sbend(sb); add_branch = au_br_alloc(sb, bend + 2, add->perm); err = PTR_ERR(add_branch); if (IS_ERR(add_branch)) goto out; err = au_br_init(add_branch, sb, add); if (unlikely(err)) { au_br_do_free(add_branch); goto out; } add_bindex = add->bindex; h_dentry = add->path.dentry; if (!remount) au_br_do_add(sb, h_dentry, add_branch, add_bindex); else { sysaufs_brs_del(sb, add_bindex); au_br_do_add(sb, h_dentry, add_branch, add_bindex); sysaufs_brs_add(sb, add_bindex); } if (!add_bindex) { au_cpup_attr_all(root_inode, /*force*/1); sb->s_maxbytes = h_dentry->d_sb->s_maxbytes; } else au_add_nlink(root_inode, h_dentry->d_inode); /* * this test/set prevents aufs from handling unnecesary notify events * of xino files, in case of re-adding a writable branch which was * once detached from aufs. */ if (au_xino_brid(sb) < 0 && au_br_writable(add_branch->br_perm) && !au_test_fs_bad_xino(h_dentry->d_sb) && add_branch->br_xino.xi_file && add_branch->br_xino.xi_file->f_dentry->d_parent == h_dentry) au_xino_brid_set(sb, add_branch->br_id); out: return err; }