int au_wkq_nowait(au_wkq_func_t func, void *args, struct super_block *sb) { int err; struct au_wkinfo *wkinfo; atomic_inc(&au_sbi(sb)->si_nowait.nw_len); /* * wkq_func() must free this wkinfo. * it highly depends upon the implementation of workqueue. */ err = 0; wkinfo = kmalloc(sizeof(*wkinfo), GFP_NOFS); if (wkinfo) { wkinfo->sb = sb; wkinfo->flags = !AuWkq_WAIT; wkinfo->func = func; wkinfo->args = args; wkinfo->comp = NULL; kobject_get(&au_sbi(sb)->si_kobj); __module_get(THIS_MODULE); au_wkq_run(wkinfo); } else { err = -ENOMEM; atomic_dec(&au_sbi(sb)->si_nowait.nw_len); } return err; }
int au_xigen_inc(struct inode *inode) { int err; loff_t pos; ssize_t sz; __u32 igen; struct super_block *sb; struct au_sbinfo *sbinfo; LKTRTrace("i%lu\n", (unsigned long)inode->i_ino); err = 0; sb = inode->i_sb; if (unlikely(!au_opt_test_xino(au_mntflags(sb)))) goto out; pos = inode->i_ino; pos *= sizeof(igen); igen = inode->i_generation + 1; sbinfo = au_sbi(sb); sz = xino_fwrite(sbinfo->si_xwrite, sbinfo->si_xigen, &igen, sizeof(igen), &pos); if (sz == sizeof(igen)) goto out; /* success */ err = sz; if (unlikely(sz >= 0)) { err = -EIO; AuIOErr("xigen error (%zd)\n", sz); } out: AuTraceErr(err); return err; }
static void sysrq_sb(struct super_block *sb) { char *plevel; struct au_sbinfo *sbinfo; struct file *file; plevel = au_plevel; au_plevel = KERN_WARNING; au_debug(1); sbinfo = au_sbi(sb); pr_warning("si=%lx\n", sysaufs_si_id(sbinfo)); pr_warning(AUFS_NAME ": superblock\n"); au_dpri_sb(sb); pr_warning(AUFS_NAME ": root dentry\n"); au_dpri_dentry(sb->s_root); pr_warning(AUFS_NAME ": root inode\n"); au_dpri_inode(sb->s_root->d_inode); #if 0 struct inode *i; pr_warning(AUFS_NAME ": isolated inode\n"); list_for_each_entry(i, &sb->s_inodes, i_sb_list) if (list_empty(&i->i_dentry)) au_dpri_inode(i); #endif pr_warning(AUFS_NAME ": files\n"); list_for_each_entry(file, &sb->s_files, f_u.fu_list) if (!special_file(file->f_dentry->d_inode->i_mode)) au_dpri_file(file); au_plevel = plevel; au_debug(0); }
int au_do_open_nondir(struct file *file, int flags) { int err; aufs_bindex_t bindex; struct file *h_file; struct dentry *dentry; struct au_finfo *finfo; FiMustWriteLock(file); err = 0; dentry = file->f_dentry; finfo = au_fi(file); memset(&finfo->fi_htop, 0, sizeof(finfo->fi_htop)); atomic_set(&finfo->fi_mmapped, 0); bindex = au_dbstart(dentry); h_file = au_h_open(dentry, bindex, flags, file, /*force_wr*/0); if (IS_ERR(h_file)) err = PTR_ERR(h_file); else { au_set_fbstart(file, bindex); au_set_h_fptr(file, bindex, h_file); au_update_figen(file); finfo->fi_file = file; au_sphl_add(&finfo->fi_hlist, &au_sbi(dentry->d_sb)->si_files); /* todo: necessary? */ /* file->f_ra = h_file->f_ra; */ } return err; }
static int au_wbr_create_mfs(struct dentry *dentry, int isdir __maybe_unused) { int err; struct super_block *sb; struct au_wbr_mfs *mfs; err = au_wbr_create_exp(dentry); if (err >= 0) goto out; sb = dentry->d_sb; mfs = &au_sbi(sb)->si_wbr_mfs; mutex_lock(&mfs->mfs_lock); if (time_after(jiffies, mfs->mfs_jiffy + mfs->mfs_expire) || mfs->mfs_bindex < 0 || au_br_rdonly(au_sbr(sb, mfs->mfs_bindex))) au_mfs(dentry); mutex_unlock(&mfs->mfs_lock); err = mfs->mfs_bindex; if (err >= 0) err = au_wbr_nonopq(dentry, err); out: AuDbg("b%d\n", err); return err; }
void au_fhsm_wrote(struct super_block *sb, aufs_bindex_t bindex, int force) { int err; struct au_sbinfo *sbinfo; struct au_fhsm *fhsm; struct au_branch *br; struct au_br_fhsm *bf; AuDbg("b%d, force %d\n", bindex, force); SiMustAnyLock(sb); sbinfo = au_sbi(sb); fhsm = &sbinfo->si_fhsm; if (!au_ftest_si(sbinfo, FHSM) || fhsm->fhsm_bottom == bindex) return; br = au_sbr(sb, bindex); bf = br->br_fhsm; AuDebugOn(!bf); mutex_lock(&bf->bf_lock); if (force || au_fhsm_pid(fhsm) || au_fhsm_test_jiffy(sbinfo, br)) err = au_fhsm_stfs(sb, bindex, /*rstfs*/NULL, /*do_lock*/0, /*do_notify*/1); mutex_unlock(&bf->bf_lock); }
/* * decide the branch and the parent dir where we will create a new entry. * returns new bindex or an error. * copyup the parent dir if needed. */ int au_wr_dir(struct dentry *dentry, struct dentry *src_dentry, struct au_wr_dir_args *args) { int err; aufs_bindex_t bcpup, bstart, src_bstart; const unsigned char add_entry = !!au_ftest_wrdir(args->flags, ADD_ENTRY); struct super_block *sb; struct dentry *parent; struct au_sbinfo *sbinfo; sb = dentry->d_sb; sbinfo = au_sbi(sb); parent = dget_parent(dentry); bstart = au_dbstart(dentry); bcpup = bstart; if (args->force_btgt < 0) { if (src_dentry) { src_bstart = au_dbstart(src_dentry); if (src_bstart < bstart) bcpup = src_bstart; } else if (add_entry) { err = AuWbrCreate(sbinfo, dentry, au_ftest_wrdir(args->flags, ISDIR)); bcpup = err; } if (bcpup < 0 || au_test_ro(sb, bcpup, dentry->d_inode)) { if (add_entry) err = AuWbrCopyup(sbinfo, dentry); else { if (!IS_ROOT(dentry)) { di_read_lock_parent(parent, !AuLock_IR); err = AuWbrCopyup(sbinfo, dentry); di_read_unlock(parent, !AuLock_IR); } else err = AuWbrCopyup(sbinfo, dentry); } bcpup = err; if (unlikely(err < 0)) goto out; } } else { bcpup = args->force_btgt; AuDebugOn(au_test_ro(sb, bcpup, dentry->d_inode)); } AuDbg("bstart %d, bcpup %d\n", bstart, bcpup); err = bcpup; if (bcpup == bstart) goto out; /* success */ else if (bstart < bcpup) au_update_dbrange(dentry, /*do_put_zero*/1); /* copyup the new parent into the branch we process */ err = au_wr_dir_cpup(dentry, parent, add_entry, bcpup, bstart); out: dput(parent); return err; }
static void au_br_do_del(struct super_block *sb, aufs_bindex_t bindex, struct au_branch *br) { aufs_bindex_t bend; struct au_sbinfo *sbinfo; struct dentry *root, *h_root; struct inode *inode, *h_inode; struct au_hinode *hinode; SiMustWriteLock(sb); root = sb->s_root; inode = root->d_inode; sbinfo = au_sbi(sb); bend = sbinfo->si_bend; h_root = au_h_dptr(root, bindex); hinode = au_hi(inode, bindex); h_inode = au_igrab(hinode->hi_inode); au_hiput(hinode); au_sbilist_lock(); au_br_do_del_brp(sbinfo, bindex, bend); au_br_do_del_hdp(au_di(root), bindex, bend); au_br_do_del_hip(au_ii(inode), bindex, bend); au_sbilist_unlock(); dput(h_root); iput(h_inode); au_br_do_free(br); }
static char *au_build_path(struct dentry *h_parent, struct path *h_rootpath, char *buf, int len, struct super_block *sb) { char *p; int n; AuTraceEnter(); p = d_path(h_rootpath->dentry, h_rootpath->mnt, buf, len); if (IS_ERR(p)) goto out; n = strlen(p); p = d_path(h_parent, h_rootpath->mnt, buf, len); if (IS_ERR(p)) goto out; LKTRTrace("%s\n", p); if (n != 1) p += n; LKTRTrace("%p, %s, %ld\n", p, p, (long)(p - buf)); p = d_path(sb->s_root, au_sbi(sb)->si_mnt, buf, len - strlen(p)); if (IS_ERR(p)) goto out; if (n != 1) p[strlen(p)] = '/'; LKTRTrace("%s\n", p); out: AuTraceErrPtr(p); return p; }
/* cf. aufs_rmdir() */ static int au_ren_del_whtmp(struct au_ren_args *a) { int err; struct inode *dir; dir = a->dst_dir; SiMustAnyLock(dir->i_sb); if (!au_nhash_test_longer_wh(&a->whlist, a->btgt, au_sbi(dir->i_sb)->si_dirwh) || au_test_fs_remote(a->h_dst->d_sb)) { err = au_whtmp_rmdir(dir, a->btgt, a->h_dst, &a->whlist); if (unlikely(err)) pr_warning("failed removing whtmp dir %.*s (%d), " "ignored.\n", AuDLNPair(a->h_dst), err); } else { au_nhash_wh_free(&a->thargs->whlist); a->thargs->whlist = a->whlist; a->whlist.nh_num = 0; au_whtmp_kick_rmdir(dir, a->btgt, a->h_dst, a->thargs); dput(a->h_dst); a->thargs = NULL; } return 0; }
static /* noinline_for_stack */ struct dentry *decode_by_dir_ino(struct super_block *sb, ino_t ino, ino_t dir_ino, struct au_nfsd_si_lock *nsi_lock) { struct dentry *dentry, *parent; struct path path; LKTRTrace("i%lu, diri%lu\n", (unsigned long)ino, (unsigned long)dir_ino); parent = sb->s_root; if (dir_ino != AUFS_ROOT_INO) { parent = decode_by_ino(sb, dir_ino, 0); dentry = parent; if (!parent) goto out; if (IS_ERR(parent)) goto out; AuDebugOn(au_test_anon(parent)); } else dget(parent); path.dentry = parent; path.mnt = au_sbi(sb)->si_mnt; dentry = au_lkup_by_ino(&path, ino, nsi_lock); dput(parent); out: AuTraceErrPtr(dentry); return dentry; }
static int au_wbr_create_mfs(struct dentry *dentry, unsigned int flags) { int err; struct dentry *parent; struct super_block *sb; struct au_wbr_mfs *mfs; err = au_wbr_create_exp(dentry); if (err >= 0) goto out; sb = dentry->d_sb; parent = NULL; if (au_ftest_wbr(flags, PARENT)) parent = dget_parent(dentry); mfs = &au_sbi(sb)->si_wbr_mfs; mutex_lock(&mfs->mfs_lock); if (time_after(jiffies, mfs->mfs_jiffy + mfs->mfs_expire) || mfs->mfs_bindex < 0 || au_br_rdonly(au_sbr(sb, mfs->mfs_bindex))) au_mfs(dentry, parent); mutex_unlock(&mfs->mfs_lock); err = mfs->mfs_bindex; dput(parent); if (err >= 0) err = au_wbr_nonopq(dentry, err); out: AuDbg("b%d\n", err); return err; }
static void au_do_dir_ts(void *arg) { struct au_dir_ts_arg *a = arg; struct au_dtime dt; struct path h_path; struct inode *dir, *h_dir; struct super_block *sb; struct au_branch *br; struct au_hinode *hdir; int err; aufs_bindex_t btop, bindex; sb = a->dentry->d_sb; if (d_really_is_negative(a->dentry)) goto out; /* no dir->i_mutex lock */ aufs_read_lock(a->dentry, AuLock_DW); /* noflush */ dir = d_inode(a->dentry); btop = au_ibtop(dir); bindex = au_br_index(sb, a->brid); if (bindex < btop) goto out_unlock; br = au_sbr(sb, bindex); h_path.dentry = au_h_dptr(a->dentry, bindex); if (!h_path.dentry) goto out_unlock; h_path.mnt = au_br_mnt(br); au_dtime_store(&dt, a->dentry, &h_path); br = au_sbr(sb, btop); if (!au_br_writable(br->br_perm)) goto out_unlock; h_path.dentry = au_h_dptr(a->dentry, btop); h_path.mnt = au_br_mnt(br); err = vfsub_mnt_want_write(h_path.mnt); if (err) goto out_unlock; hdir = au_hi(dir, btop); au_hn_inode_lock_nested(hdir, AuLsc_I_PARENT); h_dir = au_h_iptr(dir, btop); if (h_dir->i_nlink && timespec_compare(&h_dir->i_mtime, &dt.dt_mtime) < 0) { dt.dt_h_path = h_path; au_dtime_revert(&dt); } au_hn_inode_unlock(hdir); vfsub_mnt_drop_write(h_path.mnt); au_cpup_attr_timesizes(dir); out_unlock: aufs_read_unlock(a->dentry, AuLock_DW); out: dput(a->dentry); au_nwt_done(&au_sbi(sb)->si_nowait); kfree(arg); }
/* * during a user process maintains the pseudo-links, * prohibit adding a new plink and branch manipulation. */ void au_plink_maint_block(struct super_block *sb) { struct au_sbinfo *sbi = au_sbi(sb); SiMustAnyLock(sb); /* gave up wake_up_bit() */ wait_event(sbi->si_plink_wq, !sbi->si_plink_maint); }
/* * during a user process maintains the pseudo-links, * prohibit adding a new plink and branch manipulation. */ void au_plink_block_maintain(struct super_block *sb) { struct au_sbinfo *sbi = au_sbi(sb); SiMustAnyLock(sb); /* gave up wake_up_bit() */ wait_event(sbi->si_plink_wq, !au_ftest_si(sbi, MAINTAIN_PLINK)); }
void au_xigen_clr(struct super_block *sb) { struct au_sbinfo *sbinfo; sbinfo = au_sbi(sb); if (sbinfo->si_xigen) { fput(sbinfo->si_xigen); sbinfo->si_xigen = NULL; } }
int si_pid_test_slow(struct super_block *sb) { void *p; rcu_read_lock(); p = radix_tree_lookup(&au_sbi(sb)->au_si_pid.tree, current->pid); rcu_read_unlock(); return (long)!!p; }
static void sysrq_sb(struct super_block *sb) { char *plevel; struct inode *i; struct au_sbinfo *sbinfo; struct file *file; plevel = au_plevel; au_plevel = KERN_WARNING; au_debug_on(); sbinfo = au_sbi(sb); pr_warning("si=%lx\n", au_si_mask ^ (unsigned long)sbinfo); pr_warning(AUFS_NAME ": superblock\n"); au_dpri_sb(sb); pr_warning(AUFS_NAME ": root dentry\n"); au_dpri_dentry(sb->s_root); pr_warning(AUFS_NAME ": root inode\n"); au_dpri_inode(sb->s_root->d_inode); pr_warning(AUFS_NAME ": isolated inode\n"); list_for_each_entry(i, &sb->s_inodes, i_sb_list) if (list_empty(&i->i_dentry)) au_dpri_inode(i); pr_warning(AUFS_NAME ": files\n"); list_for_each_entry(file, &sb->s_files, f_u.fu_list) if (au_test_aufs_file(file)) au_dpri_file(file); #ifdef CONFIG_AUFS_DEBUG_LOCK { struct au_dbg_lock *p; struct list_head *head; pr_warning(AUFS_NAME ": locking si\n"); head = &sbinfo->si_dbg_lock[AuDbgLock_SI_LOCKING].head; list_for_each_entry(p, head, list) pr_warning("pid: %d, 0x%x\n", p->pid, p->flags); pr_warning(AUFS_NAME ": locked si\n"); head = &sbinfo->si_dbg_lock[AuDbgLock_SI_LOCKED].head; list_for_each_entry(p, head, list) pr_warning("pid: %d, 0x%x\n", p->pid, p->flags); pr_warning(AUFS_NAME ": locking di\n"); head = &sbinfo->si_dbg_lock[AuDbgLock_DI_LOCKING].head; list_for_each_entry(p, head, list) { pr_warning("pid: %d, 0x%x, %d\n", p->pid, p->flags, p->lsc); au_dpri_dentry(p->dentry); } pr_warning(AUFS_NAME ": locked di\n"); head = &sbinfo->si_dbg_lock[AuDbgLock_DI_LOCKED].head; list_for_each_entry(p, head, list) { pr_warning("pid: %d, 0x%x, %d\n", p->pid, p->flags, p->lsc); au_dpri_dentry(p->dentry); }
/* most free space */ static void au_mfs(struct dentry *dentry) { struct super_block *sb; struct au_branch *br; struct au_wbr_mfs *mfs; aufs_bindex_t bindex, bend; int err; unsigned long long b, bavail; struct path h_path; /* reduce the stack usage */ struct kstatfs *st; st = kmalloc(sizeof(*st), GFP_NOFS); if (unlikely(!st)) { AuWarn1("failed updating mfs(%d), ignored\n", -ENOMEM); return; } bavail = 0; sb = dentry->d_sb; mfs = &au_sbi(sb)->si_wbr_mfs; MtxMustLock(&mfs->mfs_lock); mfs->mfs_bindex = -EROFS; mfs->mfsrr_bytes = 0; bend = au_sbend(sb); for (bindex = 0; bindex <= bend; bindex++) { br = au_sbr(sb, bindex); if (au_br_rdonly(br)) continue; /* sb->s_root for NFS is unreliable */ h_path.mnt = br->br_mnt; h_path.dentry = h_path.mnt->mnt_root; err = vfs_statfs(&h_path, st); if (unlikely(err)) { AuWarn1("failed statfs, b%d, %d\n", bindex, err); continue; } /* when the available size is equal, select the lower one */ BUILD_BUG_ON(sizeof(b) < sizeof(st->f_bavail) || sizeof(b) < sizeof(st->f_bsize)); b = st->f_bavail * st->f_bsize; br->br_wbr->wbr_bytes = b; if (b >= bavail) { bavail = b; mfs->mfs_bindex = bindex; mfs->mfs_jiffy = jiffies; } } mfs->mfsrr_bytes = bavail; AuDbg("b%d\n", mfs->mfs_bindex); kfree(st); }
static int aufs_commit_metadata(struct inode *inode) { int err; aufs_bindex_t bindex; struct super_block *sb; struct inode *h_inode; int (*f)(struct inode *inode); sb = inode->i_sb; si_read_lock(sb, AuLock_FLUSH); ii_write_lock_child(inode); bindex = au_ibstart(inode); AuDebugOn(bindex < 0); h_inode = au_h_iptr(inode, bindex); f = h_inode->i_sb->s_export_op->commit_metadata; if (f) err = f(h_inode); else { struct writeback_control wbc = { .sync_mode = WB_SYNC_ALL, .nr_to_write = 0 /* metadata only */ }; err = sync_inode(h_inode, &wbc); } au_cpup_attr_timesizes(inode); ii_write_unlock(inode); si_read_unlock(sb); return err; } /* ---------------------------------------------------------------------- */ static struct export_operations aufs_export_op = { .fh_to_dentry = aufs_fh_to_dentry, /* .fh_to_parent = aufs_fh_to_parent, */ .encode_fh = aufs_encode_fh, .commit_metadata = aufs_commit_metadata }; void au_export_init(struct super_block *sb) { struct au_sbinfo *sbinfo; __u32 u; sb->s_export_op = &aufs_export_op; sbinfo = au_sbi(sb); sbinfo->si_xigen = NULL; get_random_bytes(&u, sizeof(u)); BUILD_BUG_ON(sizeof(u) != sizeof(int)); atomic_set(&sbinfo->si_xigen_next, u); }
int au_opts_remount(struct super_block *sb, struct au_opts *opts) { int err, rerr; unsigned char no_dreval; struct inode *dir; struct au_opt_xino *opt_xino; struct au_opt *opt; struct au_sbinfo *sbinfo; SiMustWriteLock(sb); err = 0; dir = d_inode(sb->s_root); sbinfo = au_sbi(sb); opt_xino = NULL; opt = opts->opt; while (err >= 0 && opt->type != Opt_tail) { err = au_opt_simple(sb, opt, opts); if (!err) err = au_opt_br(sb, opt, opts); if (!err) err = au_opt_xino(sb, opt, &opt_xino, opts); opt++; } if (err > 0) err = 0; AuTraceErr(err); /* go on even err */ no_dreval = !!au_ftest_si(sbinfo, NO_DREVAL); rerr = au_opts_verify(sb, opts->sb_flags, /*pending*/0); if (unlikely(rerr && !err)) err = rerr; if (no_dreval != !!au_ftest_si(sbinfo, NO_DREVAL)) au_fset_opts(opts->flags, REFRESH_IDOP); if (au_ftest_opts(opts->flags, TRUNC_XIB)) { rerr = au_xib_trunc(sb); if (unlikely(rerr && !err)) err = rerr; } /* will be handled by the caller */ if (!au_ftest_opts(opts->flags, REFRESH) && (opts->given_udba || au_opt_test(sbinfo->si_mntflags, XINO) || au_ftest_opts(opts->flags, REFRESH_IDOP) )) au_fset_opts(opts->flags, REFRESH); AuDbg("status 0x%x\n", opts->flags); return err; }
static int au_wbr_create_init_mfs(struct super_block *sb) { struct au_wbr_mfs *mfs; mfs = &au_sbi(sb)->si_wbr_mfs; mutex_init(&mfs->mfs_lock); mfs->mfs_jiffy = 0; mfs->mfs_bindex = -EROFS; return 0; }
/* round robin */ static int au_wbr_create_init_rr(struct super_block *sb) { int err; err = au_wbr_bu(sb, au_sbend(sb)); atomic_set(&au_sbi(sb)->si_wbr_rr_next, -err); /* less important */ /* smp_mb(); */ AuDbg("b%d\n", err); return err; }
unsigned int au_sigen_inc(struct super_block *sb) { unsigned int gen; SiMustWriteLock(sb); gen = ++au_sbi(sb)->si_generation; au_update_digen(sb->s_root); au_update_iigen(sb->s_root->d_inode, /*half*/0); sb->s_root->d_inode->i_version++; return gen; }
void au_fhsm_set_bottom(struct super_block *sb, aufs_bindex_t bindex) { struct au_sbinfo *sbinfo; struct au_fhsm *fhsm; SiMustWriteLock(sb); sbinfo = au_sbi(sb); fhsm = &sbinfo->si_fhsm; AuDebugOn(!fhsm); fhsm->fhsm_bottom = bindex; }
/* * decide if a new whiteout for @dentry is necessary or not. * when it is necessary, prepare the parent dir for the upper branch whose * branch index is @bcpup for creation. the actual creation of the whiteout will * be done by caller. * return value: * 0: wh is unnecessary * plus: wh is necessary * minus: error */ int au_wr_dir_need_wh(struct dentry *dentry, int isdir, aufs_bindex_t *bcpup) { int need_wh, err; aufs_bindex_t bstart; struct super_block *sb; sb = dentry->d_sb; bstart = au_dbstart(dentry); if (*bcpup < 0) { *bcpup = bstart; if (au_test_ro(sb, bstart, dentry->d_inode)) { err = AuWbrCopyup(au_sbi(sb), dentry); *bcpup = err; if (unlikely(err < 0)) goto out; } } else AuDebugOn(bstart < *bcpup || au_test_ro(sb, *bcpup, dentry->d_inode)); AuDbg("bcpup %d, bstart %d\n", *bcpup, bstart); if (*bcpup != bstart) { err = au_cpup_dirs(dentry, *bcpup); if (unlikely(err)) goto out; need_wh = 1; } else { aufs_bindex_t old_bend, new_bend, bdiropq = -1; old_bend = au_dbend(dentry); if (isdir) { bdiropq = au_dbdiropq(dentry); au_set_dbdiropq(dentry, -1); } need_wh = au_lkup_dentry(dentry, bstart + 1, /*type*/0, /*nd*/NULL); err = need_wh; if (isdir) au_set_dbdiropq(dentry, bdiropq); if (unlikely(err < 0)) goto out; new_bend = au_dbend(dentry); if (!need_wh && old_bend != new_bend) { au_set_h_dptr(dentry, new_bend, NULL); au_set_dbend(dentry, old_bend); } } AuDbg("need_wh %d\n", need_wh); err = need_wh; out: return err; }
static aufs_bindex_t au_fhsm_bottom(struct super_block *sb) { struct au_sbinfo *sbinfo; struct au_fhsm *fhsm; SiMustAnyLock(sb); sbinfo = au_sbi(sb); fhsm = &sbinfo->si_fhsm; AuDebugOn(!fhsm); return fhsm->fhsm_bottom; }
void si_pid_clr_slow(struct super_block *sb) { void *p; struct au_sbinfo *sbinfo; AuDebugOn(!si_pid_test_slow(sb)); sbinfo = au_sbi(sb); spin_lock(&sbinfo->au_si_pid.tree_lock); p = radix_tree_delete(&sbinfo->au_si_pid.tree, current->pid); spin_unlock(&sbinfo->au_si_pid.tree_lock); }
int au_xigen_new(struct inode *inode) { int err; loff_t pos; ssize_t sz; struct super_block *sb; struct au_sbinfo *sbinfo; struct file *file; LKTRTrace("i%lu\n", inode->i_ino); err = 0; /* todo: dirty, at mount time */ if (inode->i_ino == AUFS_ROOT_INO) goto out; sb = inode->i_sb; if (unlikely(!au_opt_test_xino(au_mntflags(sb)))) goto out; err = -EFBIG; pos = inode->i_ino; if (unlikely(Au_LOFF_MAX / sizeof(inode->i_generation) - 1 < pos)) { AuIOErr1("too large i%lld\n", pos); goto out; } pos *= sizeof(inode->i_generation); err = 0; sbinfo = au_sbi(sb); file = sbinfo->si_xigen; BUG_ON(!file); if (i_size_read(file->f_dentry->d_inode) < pos + sizeof(inode->i_generation)) { inode->i_generation = atomic_inc_return(&sbinfo->si_xigen_next); sz = xino_fwrite(sbinfo->si_xwrite, file, &inode->i_generation, sizeof(inode->i_generation), &pos); } else sz = xino_fread(sbinfo->si_xread, file, &inode->i_generation, sizeof(inode->i_generation), &pos); if (sz == sizeof(inode->i_generation)) goto out; /* success */ err = sz; if (unlikely(sz >= 0)) { err = -EIO; AuIOErr("xigen error (%zd)\n", sz); } out: AuTraceErr(err); return err; }
int sysaufs_si_xi_path(struct seq_file *seq, struct super_block *sb) { int err; SiMustAnyLock(sb); err = 0; if (au_opt_test(au_mntflags(sb), XINO)) { err = au_xino_path(seq, au_sbi(sb)->si_xib); seq_putc(seq, '\n'); } return err; }