if (!lower_dentry || !lower_dentry->d_op
|| !lower_dentry->d_op->d_revalidate)
continue;
- if (!lower_dentry->d_op->d_revalidate(lower_dentry,
- &lowernd))
+ /*
+ * Don't pass nameidata to lower file system, because we
+ * don't want an arbitrary lower file being opened or
+ * returned to us: it may be useless to us because of the
+ * fanout nature of unionfs (cf. file/directory open-file
+ * invariants). We will open lower files as and when needed
+ * later on.
+ */
+ if (!lower_dentry->d_op->d_revalidate(lower_dentry, NULL))
valid = false;
}
struct dentry *lower_parent_dentry = NULL;
char *name = NULL;
int valid = 0;
+ struct nameidata lower_nd;
unionfs_read_lock(dentry->d_sb);
unionfs_lock_dentry(dentry);
goto out;
}
- err = vfs_create(lower_parent_dentry->d_inode, lower_dentry, mode, nd);
+ err = init_lower_nd(&lower_nd, LOOKUP_CREATE);
+ if (err < 0)
+ goto out;
+ err = vfs_create(lower_parent_dentry->d_inode, lower_dentry, mode,
+ &lower_nd);
+ release_lower_nd(&lower_nd, err);
if (!err) {
err = PTR_ERR(unionfs_interpose(dentry, parent->i_sb, 0));
* Inside that nd structure, this function may also return an allocated
* struct file (for open intents). The caller, when done with this nd, must
* kfree the intent file (using release_lower_nd).
+ *
+ * XXX: this code, and the callers of this code, should be redone using
+ * vfs_path_lookup() when (1) the nameidata structure is refactored into a
+ * separate intent-structure, and (2) open_namei() is broken into a VFS-only
+ * function and a method that other file systems can call.
*/
int init_lower_nd(struct nameidata *nd, unsigned int flags)
{
#endif /* ALLOC_LOWER_ND_FILE */
memset(nd, 0, sizeof(struct nameidata));
+ if (!flags)
+ return err;
switch (flags) {
case LOOKUP_CREATE:
- nd->flags = LOOKUP_CREATE;
- nd->intent.open.flags = FMODE_READ | FMODE_WRITE | O_CREAT;
+ nd->intent.open.flags |= O_CREAT;
+ /* fall through: shared code for create/open cases */
+ case LOOKUP_OPEN:
+ nd->flags = flags;
+ nd->intent.open.flags |= (FMODE_READ | FMODE_WRITE);
#ifdef ALLOC_LOWER_ND_FILE
file = kzalloc(sizeof(struct file), GFP_KERNEL);
if (!file) {
nd->intent.open.file = file;
#endif /* ALLOC_LOWER_ND_FILE */
break;
+ case LOOKUP_ACCESS:
+ nd->flags = flags;
+ break;
default:
/*
* We should never get here, for now.
* We can add new cases here later on.
*/
+ dprintk("unionfs: unknown nameidata flag 0x%x\n", flags);
BUG();
break;
}
{
if (!nd->intent.open.file)
return;
- if (!err)
+ else if (!err)
release_open_intent(nd);
#ifdef ALLOC_LOWER_ND_FILE
kfree(nd->intent.open.file);