void au_fi_init_once(void *_finfo) { struct au_finfo *finfo = _finfo; static struct lock_class_key aufs_fi; au_rw_init(&finfo->fi_rwsem); au_rw_class(&finfo->fi_rwsem, &aufs_fi); }
void au_di_init_once(void *_dinfo) { struct au_dinfo *dinfo = _dinfo; static struct lock_class_key aufs_di; au_rw_init(&dinfo->di_rwsem); au_rw_class(&dinfo->di_rwsem, &aufs_di); }
void au_fi_init_once(void *_finfo) { struct au_finfo *finfo = _finfo; static struct lock_class_key aufs_fi, aufs_fi_vm, aufs_fi_mmap; au_rw_init(&finfo->fi_rwsem); au_rw_class(&finfo->fi_rwsem, &aufs_fi); mutex_init(&finfo->fi_vm_mtx); lockdep_set_class(&finfo->fi_vm_mtx, &aufs_fi_vm); mutex_init(&finfo->fi_mmap); lockdep_set_class(&finfo->fi_mmap, &aufs_fi_mmap); }
int au_si_alloc(struct super_block *sb) { int err; struct au_sbinfo *sbinfo; static struct lock_class_key aufs_si; err = -ENOMEM; sbinfo = kzalloc(sizeof(*sbinfo), GFP_NOFS); if (unlikely(!sbinfo)) goto out; BUILD_BUG_ON(sizeof(unsigned long) != sizeof(*sbinfo->au_si_pid.bitmap)); sbinfo->au_si_pid.bitmap = kcalloc(BITS_TO_LONGS(PID_MAX_DEFAULT), sizeof(*sbinfo->au_si_pid.bitmap), GFP_NOFS); if (unlikely(!sbinfo->au_si_pid.bitmap)) goto out_sbinfo; /* will be reallocated separately */ sbinfo->si_branch = kzalloc(sizeof(*sbinfo->si_branch), GFP_NOFS); if (unlikely(!sbinfo->si_branch)) goto out_pidmap; err = sysaufs_si_init(sbinfo); if (unlikely(err)) goto out_br; au_nwt_init(&sbinfo->si_nowait); au_rw_init_wlock(&sbinfo->si_rwsem); au_rw_class(&sbinfo->si_rwsem, &aufs_si); spin_lock_init(&sbinfo->au_si_pid.tree_lock); INIT_RADIX_TREE(&sbinfo->au_si_pid.tree, GFP_ATOMIC | __GFP_NOFAIL); atomic_long_set(&sbinfo->si_ninodes, 0); atomic_long_set(&sbinfo->si_nfiles, 0); sbinfo->si_bend = -1; sbinfo->si_wbr_copyup = AuWbrCopyup_Def; sbinfo->si_wbr_create = AuWbrCreate_Def; sbinfo->si_wbr_copyup_ops = au_wbr_copyup_ops + sbinfo->si_wbr_copyup; sbinfo->si_wbr_create_ops = au_wbr_create_ops + sbinfo->si_wbr_create; sbinfo->si_mntflags = au_opts_plink(AuOpt_Def); mutex_init(&sbinfo->si_xib_mtx); sbinfo->si_xino_brid = -1; /* leave si_xib_last_pindex and si_xib_next_bit */ sbinfo->si_rdcache = msecs_to_jiffies(AUFS_RDCACHE_DEF * MSEC_PER_SEC); sbinfo->si_rdblk = AUFS_RDBLK_DEF; sbinfo->si_rdhash = AUFS_RDHASH_DEF; sbinfo->si_dirwh = AUFS_DIRWH_DEF; au_spl_init(&sbinfo->si_plink); init_waitqueue_head(&sbinfo->si_plink_wq); spin_lock_init(&sbinfo->si_plink_maint_lock); /* leave other members for sysaufs and si_mnt. */ sbinfo->si_sb = sb; sb->s_fs_info = sbinfo; si_pid_set(sb); au_debug_sbinfo_init(sbinfo); return 0; /* success */ out_br: kfree(sbinfo->si_branch); out_pidmap: kfree(sbinfo->au_si_pid.bitmap); out_sbinfo: kfree(sbinfo); out: return err; }
static struct dentry *aufs_lookup(struct inode *dir, struct dentry *dentry, struct nameidata *nd) { struct dentry *ret, *parent; struct inode *inode; struct super_block *sb; int err, npositive, lc_idx; IMustLock(dir); sb = dir->i_sb; err = si_read_lock(sb, AuLock_FLUSH | AuLock_NOPLM); ret = ERR_PTR(err); if (unlikely(err)) goto out; ret = ERR_PTR(-ENAMETOOLONG); if (unlikely(dentry->d_name.len > AUFS_MAX_NAMELEN)) goto out_si; err = au_di_init(dentry); ret = ERR_PTR(err); if (unlikely(err)) goto out_si; inode = NULL; npositive = 0; /* suppress a warning */ parent = dentry->d_parent; /* dir inode is locked */ di_read_lock_parent(parent, AuLock_IR); err = au_alive_dir(parent); if (!err) err = au_digen_test(parent, au_sigen(sb)); if (!err) { npositive = au_lkup_dentry(dentry, au_dbstart(parent), /*type*/0, nd); err = npositive; } di_read_unlock(parent, AuLock_IR); ret = ERR_PTR(err); if (unlikely(err < 0)) goto out_unlock; if (npositive) { inode = au_new_inode(dentry, /*must_new*/0); ret = (void *)inode; } if (IS_ERR(inode)) { inode = NULL; goto out_unlock; } ret = d_splice_alias(inode, dentry); if (unlikely(IS_ERR(ret) && inode)) { ii_write_unlock(inode); lc_idx = AuLcNonDir_IIINFO; if (S_ISLNK(inode->i_mode)) lc_idx = AuLcSymlink_IIINFO; else if (S_ISDIR(inode->i_mode)) lc_idx = AuLcDir_IIINFO; au_rw_class(&au_ii(inode)->ii_rwsem, au_lc_key + lc_idx); iput(inode); } out_unlock: di_write_unlock(dentry); if (unlikely(IS_ERR(ret) && inode)) { lc_idx = AuLcNonDir_DIINFO; if (S_ISLNK(inode->i_mode)) lc_idx = AuLcSymlink_DIINFO; else if (S_ISDIR(inode->i_mode)) lc_idx = AuLcDir_DIINFO; au_rw_class(&au_di(dentry)->di_rwsem, au_lc_key + lc_idx); } out_si: si_read_unlock(sb); out: return ret; }
/* todo: return with unlocked? */ struct inode *au_new_inode(struct dentry *dentry, int must_new) { struct inode *inode, *h_inode; struct dentry *h_dentry; struct super_block *sb; struct mutex *mtx; ino_t h_ino, ino; int err; aufs_bindex_t bstart; sb = dentry->d_sb; bstart = au_dbstart(dentry); h_dentry = au_h_dptr(dentry, bstart); h_inode = h_dentry->d_inode; h_ino = h_inode->i_ino; /* * stop 'race'-ing between hardlinks under different * parents. */ mtx = NULL; if (!S_ISDIR(h_inode->i_mode)) mtx = &au_sbr(sb, bstart)->br_xino.xi_nondir_mtx; new_ino: if (mtx) mutex_lock(mtx); err = au_xino_read(sb, bstart, h_ino, &ino); inode = ERR_PTR(err); if (unlikely(err)) goto out; if (!ino) { ino = au_xino_new_ino(sb); if (unlikely(!ino)) { inode = ERR_PTR(-EIO); goto out; } } AuDbg("i%lu\n", (unsigned long)ino); inode = au_iget_locked(sb, ino); err = PTR_ERR(inode); if (IS_ERR(inode)) goto out; AuDbg("%lx, new %d\n", inode->i_state, !!(inode->i_state & I_NEW)); if (inode->i_state & I_NEW) { /* verbose coding for lock class name */ if (unlikely(S_ISLNK(h_inode->i_mode))) au_rw_class(&au_ii(inode)->ii_rwsem, au_lc_key + AuLcSymlink_IIINFO); else if (unlikely(S_ISDIR(h_inode->i_mode))) au_rw_class(&au_ii(inode)->ii_rwsem, au_lc_key + AuLcDir_IIINFO); else /* likely */ au_rw_class(&au_ii(inode)->ii_rwsem, au_lc_key + AuLcNonDir_IIINFO); ii_write_lock_new_child(inode); err = set_inode(inode, dentry); if (!err) { unlock_new_inode(inode); goto out; /* success */ } /* * iget_failed() calls iput(), but we need to call * ii_write_unlock() after iget_failed(). so dirty hack for * i_count. */ atomic_inc(&inode->i_count); iget_failed(inode); ii_write_unlock(inode); au_xino_write(sb, bstart, h_ino, /*ino*/0); /* ignore this error */ goto out_iput; } else if (!must_new && !IS_DEADDIR(inode) && inode->i_nlink) { /* * horrible race condition between lookup, readdir and copyup * (or something). */ if (mtx) mutex_unlock(mtx); err = reval_inode(inode, dentry); if (unlikely(err < 0)) { mtx = NULL; goto out_iput; } if (!err) { mtx = NULL; goto out; /* success */ } else if (mtx) mutex_lock(mtx); } if (unlikely(au_test_fs_unique_ino(h_dentry->d_inode))) AuWarn1("Warning: Un-notified UDBA or repeatedly renamed dir," " b%d, %s, %pd, hi%lu, i%lu.\n", bstart, au_sbtype(h_dentry->d_sb), dentry, (unsigned long)h_ino, (unsigned long)ino); ino = 0; err = au_xino_write(sb, bstart, h_ino, /*ino*/0); if (!err) { iput(inode); if (mtx) mutex_unlock(mtx); goto new_ino; } out_iput: iput(inode); inode = ERR_PTR(err); out: if (mtx) mutex_unlock(mtx); return inode; }
static struct dentry *aufs_lookup(struct inode *dir, struct dentry *dentry, unsigned int flags) { struct dentry *ret, *parent; struct inode *inode; struct super_block *sb; int err, npositive; IMustLock(dir); /* todo: support rcu-walk? */ ret = ERR_PTR(-ECHILD); if (flags & LOOKUP_RCU) goto out; ret = ERR_PTR(-ENAMETOOLONG); if (unlikely(dentry->d_name.len > AUFS_MAX_NAMELEN)) goto out; sb = dir->i_sb; err = si_read_lock(sb, AuLock_FLUSH | AuLock_NOPLM); ret = ERR_PTR(err); if (unlikely(err)) goto out; err = au_di_init(dentry); ret = ERR_PTR(err); if (unlikely(err)) goto out_si; inode = NULL; npositive = 0; /* suppress a warning */ parent = dentry->d_parent; /* dir inode is locked */ di_read_lock_parent(parent, AuLock_IR); err = au_alive_dir(parent); if (!err) err = au_digen_test(parent, au_sigen(sb)); if (!err) { npositive = au_lkup_dentry(dentry, au_dbstart(parent), /*type*/0); err = npositive; } di_read_unlock(parent, AuLock_IR); ret = ERR_PTR(err); if (unlikely(err < 0)) goto out_unlock; if (npositive) { inode = au_new_inode(dentry, /*must_new*/0); if (IS_ERR(inode)) { ret = (void *)inode; inode = NULL; goto out_unlock; } } if (inode) atomic_inc(&inode->i_count); ret = d_splice_alias(inode, dentry); #if 0 if (unlikely(d_need_lookup(dentry))) { spin_lock(&dentry->d_lock); dentry->d_flags &= ~DCACHE_NEED_LOOKUP; spin_unlock(&dentry->d_lock); } else #endif if (inode) { if (!IS_ERR(ret)) { iput(inode); if (ret && ret != dentry) ii_write_unlock(inode); } else { ii_write_unlock(inode); iput(inode); inode = NULL; } } out_unlock: di_write_unlock(dentry); if (inode) { /* verbose coding for lock class name */ if (unlikely(S_ISLNK(inode->i_mode))) au_rw_class(&au_di(dentry)->di_rwsem, au_lc_key + AuLcSymlink_DIINFO); else if (unlikely(S_ISDIR(inode->i_mode))) au_rw_class(&au_di(dentry)->di_rwsem, au_lc_key + AuLcDir_DIINFO); else /* likely */ au_rw_class(&au_di(dentry)->di_rwsem, au_lc_key + AuLcNonDir_DIINFO); } out_si: si_read_unlock(sb); out: return ret; }