void au_set_h_dptr(struct dentry *dentry, aufs_bindex_t bindex, struct dentry *h_dentry) { struct au_hdentry *hd = au_di(dentry)->di_hdentry + bindex; DiMustWriteLock(dentry); AuDebugOn(bindex < au_di(dentry)->di_bstart || bindex > au_di(dentry)->di_bend || (h_dentry && atomic_read(&h_dentry->d_count) <= 0) || (h_dentry && hd->hd_dentry) ); if (hd->hd_dentry) au_hdput(hd, /*do_free*/0); hd->hd_dentry = h_dentry; }
int au_dcsub_pages(struct au_dcsub_pages *dpages, struct dentry *root, au_dpages_test test, void *arg) { int err; struct dentry *this_parent = root; struct list_head *next; struct super_block *sb = root->d_sb; err = 0; spin_lock(&dcache_lock); repeat: next = this_parent->d_subdirs.next; resume: if (this_parent->d_sb == sb && !IS_ROOT(this_parent) && au_di(this_parent) && (!test || test(this_parent, arg))) { err = au_dpages_append(dpages, this_parent, GFP_ATOMIC); if (unlikely(err)) goto out; } while (next != &this_parent->d_subdirs) { struct list_head *tmp = next; struct dentry *dentry = list_entry(tmp, struct dentry, d_u.d_child); next = tmp->next; if (!list_empty(&dentry->d_subdirs)) { this_parent = dentry; goto repeat; } if (dentry->d_sb == sb && au_di(dentry) && (!test || test(dentry, arg))) { err = au_dpages_append(dpages, dentry, GFP_ATOMIC); if (unlikely(err)) goto out; } } if (this_parent != root) { next = this_parent->d_u.d_child.next; this_parent = this_parent->d_parent; /* dcache_lock is locked */ goto resume; } out: spin_unlock(&dcache_lock); return err; }
void di_write_unlock(struct dentry *d) { au_dbg_verify_dinode(d); if (d->d_inode) ii_write_unlock(d->d_inode); au_rw_write_unlock(&au_di(d)->di_rwsem); }
static void aufs_d_release(struct dentry *dentry) { if (au_di(dentry)) { au_di_fin(dentry); au_hn_di_reinit(dentry); } }
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); }
void di_write_unlock2(struct dentry *d1, struct dentry *d2) { di_write_unlock(d1); if (d1->d_inode == d2->d_inode) au_rw_write_unlock(&au_di(d2)->di_rwsem); else di_write_unlock(d2); }
void di_downgrade_lock(struct dentry *d, int flags) { SiMustAnyLock(d->d_sb); au_rw_dgrade_lock(&au_di(d)->di_rwsem); if (d->d_inode && au_ftest_lock(flags, IR)) ii_downgrade_lock(d->d_inode); }
void au_di_fin(struct dentry *dentry) { struct au_dinfo *dinfo; dinfo = au_di(dentry); AuRwDestroy(&dinfo->di_rwsem); au_di_free(dinfo); }
void di_write_unlock2(struct dentry *d1, struct dentry *d2) { di_write_unlock(d1); if (d1->d_inode == d2->d_inode) { au_rw_write_unlock(&au_di(d2)->di_rwsem); au_dbg_locked_di_unreg(d2, AuLock_IW); } else di_write_unlock(d2); }
void di_write_unlock(struct dentry *d) { LKTRTrace("%.*s\n", AuDLNPair(d)); SiMustAnyLock(d->d_sb); if (d->d_inode) ii_write_unlock(d->d_inode); au_rw_write_unlock(&au_di(d)->di_rwsem); au_dbg_locked_di_unreg(d, AuLock_IW); }
void di_read_unlock(struct dentry *d, int flags) { if (d->d_inode) { if (au_ftest_lock(flags, IW)) ii_write_unlock(d->d_inode); else if (au_ftest_lock(flags, IR)) ii_read_unlock(d->d_inode); } au_rw_read_unlock(&au_di(d)->di_rwsem); }
void di_read_lock(struct dentry *d, int flags, unsigned int lsc) { au_rw_read_lock_nested(&au_di(d)->di_rwsem, lsc); if (d->d_inode) { if (au_ftest_lock(flags, IW)) do_ii_write_lock(d->d_inode, lsc); else if (au_ftest_lock(flags, IR)) do_ii_read_lock(d->d_inode, lsc); } }
void au_set_h_dptr(struct dentry *dentry, aufs_bindex_t bindex, struct dentry *h_dentry) { struct au_hdentry *hd = au_di(dentry)->di_hdentry + bindex; DiMustWriteLock(dentry); if (hd->hd_dentry) au_hdput(hd); hd->hd_dentry = h_dentry; }
void au_set_dbdiropq(struct dentry *dentry, aufs_bindex_t bindex) { DiMustWriteLock(dentry); AuDebugOn(au_sbend(dentry->d_sb) < bindex); AuDebugOn((bindex >= 0 && (bindex < au_dbstart(dentry) || au_dbend(dentry) < bindex)) || (dentry->d_inode && dentry->d_inode->i_mode && !S_ISDIR(dentry->d_inode->i_mode))); au_di(dentry)->di_bdiropq = bindex; }
struct dentry *au_h_dptr(struct dentry *dentry, aufs_bindex_t bindex) { struct dentry *d; DiMustAnyLock(dentry); if (au_dbstart(dentry) < 0 || bindex < au_dbstart(dentry)) return NULL; AuDebugOn(bindex < 0 /* || bindex > au_sbend(dentry->d_sb) */); d = au_di(dentry)->di_hdentry[0 + bindex].hd_dentry; AuDebugOn(d && (atomic_read(&d->d_count) <= 0)); return d; }
struct dentry *au_h_dptr(struct dentry *dentry, aufs_bindex_t bindex) { struct dentry *d; DiMustAnyLock(dentry); if (au_dbstart(dentry) < 0 || bindex < au_dbstart(dentry)) return NULL; AuDebugOn(bindex < 0); d = au_di(dentry)->di_hdentry[0 + bindex].hd_dentry; AuDebugOn(d && au_dcount(d) <= 0); return d; }
void di_read_unlock(struct dentry *d, int flags) { if (d->d_inode) { if (au_ftest_lock(flags, IW)) { au_dbg_verify_dinode(d); ii_write_unlock(d->d_inode); } else if (au_ftest_lock(flags, IR)) { au_dbg_verify_dinode(d); ii_read_unlock(d->d_inode); } } au_rw_read_unlock(&au_di(d)->di_rwsem); }
void di_write_lock(struct dentry *d, unsigned int lsc) { LKTRTrace("%.*s, %u\n", AuDLNPair(d), lsc); SiMustAnyLock(d->d_sb); /* todo: always nested? */ au_dbg_locking_di_reg(d, AuLock_IW, lsc); au_rw_write_lock_nested(&au_di(d)->di_rwsem, lsc); au_dbg_locking_di_unreg(d, AuLock_IW); au_dbg_locked_di_reg(d, AuLock_IW, lsc); if (d->d_inode) do_ii_write_lock(d->d_inode, lsc); }
void di_read_unlock(struct dentry *d, int flags) { LKTRTrace("%.*s\n", AuDLNPair(d)); SiMustAnyLock(d->d_sb); if (d->d_inode) { if (au_ftest_lock(flags, IW)) ii_write_unlock(d->d_inode); else if (au_ftest_lock(flags, IR)) ii_read_unlock(d->d_inode); } au_rw_read_unlock(&au_di(d)->di_rwsem); au_dbg_locked_di_unreg(d, flags); }
/* * 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 { struct au_dinfo *dinfo, *tmp; need_wh = -ENOMEM; dinfo = au_di(dentry); tmp = au_di_alloc(sb, AuLsc_DI_TMP); if (tmp) { au_di_cp(tmp, dinfo); au_di_swap(tmp, dinfo); /* returns the number of positive dentries */ need_wh = au_lkup_dentry(dentry, bstart + 1, /*type*/0, /*nd*/NULL); au_di_swap(tmp, dinfo); au_rw_write_unlock(&tmp->di_rwsem); au_di_free(tmp); } } AuDbg("need_wh %d\n", need_wh); err = need_wh; out: return err; }
void au_set_h_dptr(struct dentry *dentry, aufs_bindex_t bindex, struct dentry *h_dentry) { struct au_hdentry *hd = au_di(dentry)->di_hdentry + bindex; struct au_branch *br; DiMustWriteLock(dentry); au_hdput(hd); hd->hd_dentry = h_dentry; if (h_dentry) { br = au_sbr(dentry->d_sb, bindex); hd->hd_id = br->br_id; } }
void di_read_lock(struct dentry *d, int flags, unsigned int lsc) { LKTRTrace("%.*s, %u\n", AuDLNPair(d), lsc); SiMustAnyLock(d->d_sb); /* todo: always nested? */ au_dbg_locking_di_reg(d, flags, lsc); au_rw_read_lock_nested(&au_di(d)->di_rwsem, lsc); au_dbg_locking_di_unreg(d, flags); au_dbg_locked_di_reg(d, flags, lsc); if (d->d_inode) { if (au_ftest_lock(flags, IW)) do_ii_write_lock(d->d_inode, lsc); else if (au_ftest_lock(flags, IR)) do_ii_read_lock(d->d_inode, lsc); } }
static void au_br_do_add(struct super_block *sb, struct dentry *h_dentry, struct au_branch *br, aufs_bindex_t bindex) { struct dentry *root; struct inode *root_inode; aufs_bindex_t bend, amount; root = sb->s_root; root_inode = root->d_inode; bend = au_sbend(sb); amount = bend + 1 - bindex; au_br_do_add_brp(au_sbi(sb), bindex, br, bend, amount); au_br_do_add_hdp(au_di(root), bindex, bend, amount); au_br_do_add_hip(au_ii(root_inode), bindex, bend, amount); au_set_h_dptr(root, bindex, dget(h_dentry)); au_set_h_iptr(root_inode, bindex, au_igrab(h_dentry->d_inode), /*flags*/0); }
/* * returns the number of found lower positive dentries, * otherwise an error. */ int au_refresh_hdentry(struct dentry *dentry, mode_t type) { int npositive, err; unsigned int sigen; aufs_bindex_t bstart; struct au_dinfo *dinfo; struct super_block *sb; struct dentry *parent; DiMustWriteLock(dentry); sb = dentry->d_sb; AuDebugOn(IS_ROOT(dentry)); sigen = au_sigen(sb); parent = dget_parent(dentry); AuDebugOn(au_digen(parent) != sigen || au_iigen(parent->d_inode) != sigen); dinfo = au_di(dentry); err = au_di_realloc(dinfo, au_sbend(sb) + 1); npositive = err; if (unlikely(err)) goto out; au_do_refresh_hdentry(dinfo->di_hdentry + dinfo->di_bstart, dinfo, parent); npositive = 0; bstart = au_dbstart(parent); if (type != S_IFDIR && dinfo->di_bstart == bstart) goto out_dgen; /* success */ npositive = au_lkup_dentry(dentry, bstart, type, /*nd*/NULL); if (npositive < 0) goto out; if (dinfo->di_bwh >= 0 && dinfo->di_bwh <= dinfo->di_bstart) d_drop(dentry); out_dgen: au_update_digen(dentry); out: dput(parent); AuTraceErr(npositive); return npositive; }
/* * returns a newly allocated branch. @new_nbranch is a number of branches * after adding a branch. */ static struct au_branch *au_br_alloc(struct super_block *sb, int new_nbranch, int perm) { struct au_branch *add_branch; struct dentry *root; int err; err = -ENOMEM; root = sb->s_root; add_branch = kmalloc(sizeof(*add_branch), GFP_NOFS); if (unlikely(!add_branch)) goto out; err = au_hnotify_init_br(add_branch, perm); if (unlikely(err)) goto out_br; add_branch->br_wbr = NULL; if (au_br_writable(perm)) { /* may be freed separately at changing the branch permission */ add_branch->br_wbr = kmalloc(sizeof(*add_branch->br_wbr), GFP_NOFS); if (unlikely(!add_branch->br_wbr)) goto out_hnotify; } err = au_sbr_realloc(au_sbi(sb), new_nbranch); if (!err) err = au_di_realloc(au_di(root), new_nbranch); if (!err) err = au_ii_realloc(au_ii(root->d_inode), new_nbranch); if (!err) return add_branch; /* success */ kfree(add_branch->br_wbr); out_hnotify: au_hnotify_fin_br(add_branch); out_br: kfree(add_branch); out: return ERR_PTR(err); }
void au_dpri_dentry(struct dentry *dentry) { struct au_dinfo *dinfo; aufs_bindex_t bindex; int err; err = do_pri_dentry(-1, dentry); if (err || !au_test_aufs(dentry->d_sb)) return; dinfo = au_di(dentry); if (!dinfo) return; dpri("d-1: bstart %d, bend %d, bwh %d, bdiropq %d, gen %d\n", dinfo->di_bstart, dinfo->di_bend, dinfo->di_bwh, dinfo->di_bdiropq, au_digen(dentry)); if (dinfo->di_bstart < 0) return; for (bindex = dinfo->di_bstart; bindex <= dinfo->di_bend; bindex++) do_pri_dentry(bindex, dinfo->di_hdentry[0 + bindex].hd_dentry); }
static int au_reopen_wh(struct file *file, aufs_bindex_t btgt, struct dentry *hi_wh) { int err; aufs_bindex_t bstart; struct au_dinfo *dinfo; struct dentry *h_dentry; dinfo = au_di(file->f_dentry); AuRwMustWriteLock(&dinfo->di_rwsem); bstart = dinfo->di_bstart; dinfo->di_bstart = btgt; h_dentry = dinfo->di_hdentry[0 + btgt].hd_dentry; dinfo->di_hdentry[0 + btgt].hd_dentry = hi_wh; err = au_reopen_nondir(file); dinfo->di_hdentry[0 + btgt].hd_dentry = h_dentry; dinfo->di_bstart = bstart; return err; }
void au_update_dbrange(struct dentry *dentry, int do_put_zero) { struct au_dinfo *dinfo; struct dentry *h_d; struct au_hdentry *hdp; DiMustWriteLock(dentry); dinfo = au_di(dentry); if (!dinfo || dinfo->di_bstart < 0) return; hdp = dinfo->di_hdentry; if (do_put_zero) { aufs_bindex_t bindex, bend; bend = dinfo->di_bend; for (bindex = dinfo->di_bstart; bindex <= bend; bindex++) { h_d = hdp[0 + bindex].hd_dentry; if (h_d && !h_d->d_inode) au_set_h_dptr(dentry, bindex, NULL); } } dinfo->di_bstart = -1; while (++dinfo->di_bstart <= dinfo->di_bend) if (hdp[0 + dinfo->di_bstart].hd_dentry) break; if (dinfo->di_bstart > dinfo->di_bend) { dinfo->di_bstart = -1; dinfo->di_bend = -1; return; } dinfo->di_bend++; while (0 <= --dinfo->di_bend) if (hdp[0 + dinfo->di_bend].hd_dentry) break; AuDebugOn(dinfo->di_bstart > dinfo->di_bend || dinfo->di_bend < 0); }
static inline int au_dcsub_dpages_aufs(struct dentry *dentry, void *arg) { return au_di(dentry) && dentry->d_sb == arg; }
void au_update_digen(struct dentry *dentry) { atomic_set(&au_di(dentry)->di_generation, au_sigen(dentry->d_sb)); /* smp_mb(); */ /* atomic_set */ }