int vfsub_sio_mkdir(struct au_hinode *hdir, struct dentry *dentry, int mode, int dlgt) { int err, do_sio, wkq_err; struct inode *dir = hdir->hi_inode; struct au_hin_ignore ign; struct vfsub_args vargs; LKTRTrace("i%lu, %.*s\n", dir->i_ino, AuDLNPair(dentry)); vfsub_args_init(&vargs, &ign, dlgt, /*force_unlink*/0); vfsub_ign_hinode(&vargs, IN_CREATE, hdir); do_sio = au_test_h_perm_sio(dir, MAY_EXEC | MAY_WRITE, dlgt); if (!do_sio) err = vfsub_mkdir(dir, dentry, mode, &vargs); else { struct au_vfsub_mkdir_args args = { .errp = &err, .dir = dir, .dentry = dentry, .mode = mode, .vargs = &vargs }; vfsub_fclr(vargs.flags, DLGT); wkq_err = au_wkq_wait(au_call_vfsub_mkdir, &args, /*dlgt*/0); if (unlikely(wkq_err)) err = wkq_err; } AuTraceErr(err); return err; }
/* todo: should this mkdir be done in /sbin/mount.aufs helper? */ static int au_whdir(struct inode *h_dir, struct path *path) { int err; err = -EEXIST; if (!path->dentry->d_inode) { int mode = S_IRWXU; if (au_test_nfs(path->dentry->d_sb)) mode |= S_IXUGO; err = vfsub_mkdir(h_dir, path, mode); } else if (S_ISDIR(path->dentry->d_inode->i_mode)) err = 0; else pr_err("unknown %.*s exists\n", AuDLNPair(path->dentry)); return err; }
int vfsub_sio_mkdir(struct inode *dir, struct path *path, int mode) { int err, do_sio, wkq_err; do_sio = au_test_h_perm_sio(dir, MAY_EXEC | MAY_WRITE); if (!do_sio) err = vfsub_mkdir(dir, path, mode); else { struct au_vfsub_mkdir_args args = { .errp = &err, .dir = dir, .path = path, .mode = mode }; wkq_err = au_wkq_wait(au_call_vfsub_mkdir, &args); if (unlikely(wkq_err)) err = wkq_err; } return err; }
static void au_call_vfsub_mkdir(void *args) { struct au_vfsub_mkdir_args *a = args; *a->errp = vfsub_mkdir(a->dir, a->path, a->mode); }
int aufs_mkdir(struct inode *dir, struct dentry *dentry, int mode) { int err, rerr; aufs_bindex_t bindex; unsigned char diropq; struct path h_path; struct dentry *wh_dentry, *parent, *opq_dentry; struct mutex *h_mtx; struct super_block *sb; struct { struct au_pin pin; struct au_dtime dt; } *a; /* reduce the stack usage */ struct au_wr_dir_args wr_dir_args = { .force_btgt = -1, .flags = AuWrDir_ADD_ENTRY | AuWrDir_ISDIR }; IMustLock(dir); err = -ENOMEM; a = kmalloc(sizeof(*a), GFP_NOFS); if (unlikely(!a)) goto out; err = aufs_read_lock(dentry, AuLock_DW | AuLock_GEN); if (unlikely(err)) goto out_free; err = au_d_may_add(dentry); if (unlikely(err)) goto out_unlock; parent = dentry->d_parent; /* dir inode is locked */ di_write_lock_parent(parent); wh_dentry = lock_hdir_lkup_wh(dentry, &a->dt, /*src_dentry*/NULL, &a->pin, &wr_dir_args); err = PTR_ERR(wh_dentry); if (IS_ERR(wh_dentry)) goto out_parent; sb = dentry->d_sb; bindex = au_dbstart(dentry); h_path.dentry = au_h_dptr(dentry, bindex); h_path.mnt = au_sbr_mnt(sb, bindex); err = vfsub_mkdir(au_pinned_h_dir(&a->pin), &h_path, mode); if (unlikely(err)) goto out_unpin; /* make the dir opaque */ diropq = 0; h_mtx = &h_path.dentry->d_inode->i_mutex; if (wh_dentry || au_opt_test(au_mntflags(sb), ALWAYS_DIROPQ)) { mutex_lock_nested(h_mtx, AuLsc_I_CHILD); opq_dentry = au_diropq_create(dentry, bindex); mutex_unlock(h_mtx); err = PTR_ERR(opq_dentry); if (IS_ERR(opq_dentry)) goto out_dir; dput(opq_dentry); diropq = 1; } err = epilog(dir, bindex, wh_dentry, dentry); if (!err) { inc_nlink(dir); goto out_unpin; /* success */ } /* revert */ if (diropq) { AuLabel(revert opq); mutex_lock_nested(h_mtx, AuLsc_I_CHILD); rerr = au_diropq_remove(dentry, bindex); mutex_unlock(h_mtx); if (rerr) { AuIOErr("%.*s reverting diropq failed(%d, %d)\n", AuDLNPair(dentry), err, rerr); err = -EIO; } } out_dir: AuLabel(revert dir); rerr = vfsub_rmdir(au_pinned_h_dir(&a->pin), &h_path); if (rerr) { AuIOErr("%.*s reverting dir failed(%d, %d)\n", AuDLNPair(dentry), err, rerr); err = -EIO; } au_dtime_revert(&a->dt); out_unpin: au_unpin(&a->pin); dput(wh_dentry); out_parent: di_write_unlock(parent); out_unlock: if (unlikely(err)) { au_update_dbstart(dentry); d_drop(dentry); } aufs_read_unlock(dentry, AuLock_DW); out_free: kfree(a); out: return err; }
static void au_call_vfsub_mkdir(void *args) { struct au_vfsub_mkdir_args *a = args; *a->errp = vfsub_mkdir(a->dir, a->dentry, a->mode, a->vargs); }