/* * Lookup one path component @name relative to a <base,mnt> path pair. * Behaves nearly the same as lookup_one_len (i.e., return negative dentry * on ENOENT), but uses the @mnt passed, so it can cross bind mounts and * other lower mounts properly. If @new_mnt is non-null, will fill in the * new mnt there. Caller is responsible to dput/mntput/path_put returned * @dentry and @new_mnt. */ struct dentry *__lookup_one(struct dentry *base, struct vfsmount *mnt, const char *name, struct vfsmount **new_mnt) { struct dentry *dentry = NULL; struct nameidata lower_nd; int err; /* we use flags=0 to get basic lookup */ err = vfs_path_lookup(base, mnt, name, 0, &lower_nd); switch (err) { case 0: /* no error */ dentry = lower_nd.path.dentry; if (new_mnt) *new_mnt = lower_nd.path.mnt; /* rc already inc'ed */ break; case -ENOENT: /* * We don't consider ENOENT an error, and we want to return * a negative dentry (ala lookup_one_len). As we know * there was no inode for this name before (-ENOENT), then * it's safe to call lookup_one_len (which doesn't take a * vfsmount). */ dentry = lookup_one_len(name, base, strlen(name)); if (new_mnt) *new_mnt = mntget(lower_nd.path.mnt); break; default: /* all other real errors */ dentry = ERR_PTR(err); break; } return dentry; }
/** * Prepares a directory operation by taking the mutex on the parent inode of * an entry and returning a dentry for the entry. * * @param child_name path to the entry, assumed absolute from configfs * scheduler subsystem entry. * * @return a valid dentry to the target entry, or error. The valid * dentry must be released with put_child_dentry. */ static struct dentry *get_child_dentry(const char *child_name) { struct dentry *d_dir; struct dentry *d_child; const char *last_child_comp; const char *real_child_name = child_name; int err; d_dir = dget(krg_scheduler_subsys.su_group.cg_item.ci_dentry); last_child_comp = strrchr(child_name, '/'); if (last_child_comp) { struct nameidata nd; err = vfs_path_lookup(d_dir, scheduler_fs_mount, child_name, LOOKUP_PARENT, &nd); dput(d_dir); if (err) return ERR_PTR(err); d_dir = dget(nd.path.dentry); path_put(&nd.path); BUG_ON(!last_child_comp[1]); real_child_name = last_child_comp + 1; } mutex_lock_nested(&d_dir->d_inode->i_mutex, I_MUTEX_PARENT); d_child = lookup_one_len(real_child_name, d_dir, strlen(real_child_name)); if (IS_ERR(d_child)) mutex_unlock(&d_dir->d_inode->i_mutex); dput(d_dir); return d_child; }
static int dev_mkdir(const char *name, mode_t mode) { struct nameidata nd; struct dentry *dentry; int err; err = vfs_path_lookup(dev_mnt->mnt_root, dev_mnt, name, LOOKUP_PARENT, &nd); if (err) return err; dentry = lookup_create(&nd, 1); if (!IS_ERR(dentry)) { err = vfs_mkdir(nd.path.dentry->d_inode, dentry, mode); if (!err) /* mark as kernel-created inode */ dentry->d_inode->i_private = &dev_mnt; dput(dentry); } else { err = PTR_ERR(dentry); } mutex_unlock(&nd.path.dentry->d_inode->i_mutex); path_put(&nd.path); return err; }
static int dev_rmdir(const char *name) { struct nameidata nd; struct dentry *dentry; int err; err = vfs_path_lookup(dev_mnt->mnt_root, dev_mnt, name, LOOKUP_PARENT, &nd); if (err) return err; mutex_lock_nested(&nd.path.dentry->d_inode->i_mutex, I_MUTEX_PARENT); dentry = lookup_one_len(nd.last.name, nd.path.dentry, nd.last.len); if (!IS_ERR(dentry)) { if (dentry->d_inode) { if (dentry->d_inode->i_private == &dev_mnt) err = vfs_rmdir(nd.path.dentry->d_inode, dentry); else err = -EPERM; } else { err = -ENOENT; } dput(dentry); } else { err = PTR_ERR(dentry); } mutex_unlock(&nd.path.dentry->d_inode->i_mutex); path_put(&nd.path); return err; }
static struct file *do_open(char *name, int flags) { struct nameidata nd; struct vfsmount *mnt; int error; mnt = do_kern_mount("nfsd", 0, "nfsd", NULL); if (IS_ERR(mnt)) return (struct file *)mnt; error = vfs_path_lookup(mnt->mnt_root, mnt, name, 0, &nd); mntput(mnt); /* drop do_kern_mount reference */ if (error) return ERR_PTR(error); if (flags == O_RDWR) error = may_open(&nd,MAY_READ|MAY_WRITE,FMODE_READ|FMODE_WRITE); else error = may_open(&nd, MAY_WRITE, FMODE_WRITE); if (!error) return dentry_open(nd.path.dentry, nd.path.mnt, flags); path_put(&nd.path); return ERR_PTR(error); }
/** * ecryptfs_lookup_one_lower * @ecryptfs_dentry: The eCryptfs dentry that we are looking up * @lower_dir_dentry: lower parent directory * * Get the lower dentry from vfs. If lower dentry does not exist yet, * create it. */ static struct dentry * ecryptfs_lookup_one_lower(struct dentry *ecryptfs_dentry, struct dentry *lower_dir_dentry) { struct nameidata nd; struct vfsmount *lower_mnt; struct qstr *name; int err; name = &ecryptfs_dentry->d_name; lower_mnt = mntget(ecryptfs_dentry_to_lower_mnt( ecryptfs_dentry->d_parent)); err = vfs_path_lookup(lower_dir_dentry, lower_mnt, name->name , 0, &nd); mntput(lower_mnt); if (!err) { /* we dont need the mount */ mntput(nd.path.mnt); return nd.path.dentry; } if (err != -ENOENT) return ERR_PTR(err); /* create a new lower dentry */ return ecryptfs_new_lower_dentry(name, lower_dir_dentry, &nd); }
/** * Look up for a file (or directory) in VFS. */ static struct dentry * lookup_file(const char *path, struct dentry *parent) { int ret; struct path p; BUG_ON(!parent); ret = vfs_path_lookup(parent, NULL, path, 0, &p); return (ret ? NULL : p.dentry); }
int devtmpfs_delete_node(struct device *dev) { const char *tmp = NULL; const char *nodename; const struct cred *curr_cred; struct nameidata nd; struct dentry *dentry; struct kstat stat; int deleted = 1; int err; if (!dev_mnt) return 0; nodename = device_get_devnode(dev, NULL, &tmp); if (!nodename) return -ENOMEM; curr_cred = override_creds(&init_cred); err = vfs_path_lookup(dev_mnt->mnt_root, dev_mnt, nodename, LOOKUP_PARENT, &nd); if (err) goto out; mutex_lock_nested(&nd.path.dentry->d_inode->i_mutex, I_MUTEX_PARENT); dentry = lookup_one_len(nd.last.name, nd.path.dentry, nd.last.len); if (!IS_ERR(dentry)) { if (dentry->d_inode) { err = vfs_getattr(nd.path.mnt, dentry, &stat); if (!err && dev_mynode(dev, dentry->d_inode, &stat)) { err = vfs_unlink(nd.path.dentry->d_inode, dentry); if (!err || err == -ENOENT) deleted = 1; } } else { err = -ENOENT; } dput(dentry); } else { err = PTR_ERR(dentry); } mutex_unlock(&nd.path.dentry->d_inode->i_mutex); path_put(&nd.path); if (deleted && strchr(nodename, '/')) delete_path(nodename); out: kfree(tmp); revert_creds(curr_cred); return err; }
void syscall_chdir(uint32_t *ebx, uint32_t *ecx, uint32_t *edx) { const char *path = (const char*) *ebx; vfs_inode_t *inode = vfs_path_lookup(path); if(inode != NULL) { if(S_ISDIR(inode->stat)) { current_proc->work_dir = inode; *ecx = 0; } else { *ecx = -1; } } else { *ecx = -2; } }
static int create_path(const char *nodepath) { char *path; struct nameidata nd; int err = 0; struct vfsmount *dev_mnt = ve_devmnt(); path = kstrdup(nodepath, GFP_KERNEL); if (!path) return -ENOMEM; err = vfs_path_lookup(dev_mnt->mnt_root, dev_mnt, path, LOOKUP_PARENT, &nd); if (err == 0) { struct dentry *dentry; /* create directory right away */ dentry = lookup_create(&nd, 1); if (!IS_ERR(dentry)) { err = vfs_mkdir(nd.path.dentry->d_inode, dentry, 0755); dput(dentry); } mutex_unlock(&nd.path.dentry->d_inode->i_mutex); path_put(&nd.path); } else if (err == -ENOENT) { char *s; /* parent directories do not exist, create them */ s = path; while (1) { s = strchr(s, '/'); if (!s) break; s[0] = '\0'; err = dev_mkdir(path, 0755); if (err && err != -EEXIST) break; s[0] = '/'; s++; } } kfree(path); return err; }
int nfs_cache_register(struct cache_detail *cd) { struct nameidata nd; struct vfsmount *mnt; int ret; mnt = rpc_get_mount(); if (IS_ERR(mnt)) return PTR_ERR(mnt); ret = vfs_path_lookup(mnt->mnt_root, mnt, "/cache", 0, &nd); if (ret) goto err; ret = sunrpc_cache_register_pipefs(nd.path.dentry, cd->name, 0600, cd); path_put(&nd.path); if (!ret) return ret; err: rpc_put_mount(); return ret; }
void syscall_open(uint32_t *ebx, uint32_t *ecx, uint32_t *edx) { const char *path = (const char*) *ebx; int oflags = *ecx; mode_t mode = *edx; vfs_inode_t *inode = vfs_path_lookup(path); fd_t fd = proc_get_unused_fd(current_proc); if(inode == NULL) { if(oflags & O_CREAT) {// create inode // TODO: what if here is a path with subdirs given? char *name = malloc(strlen((char*)path)); strcpy(name, path); inode = vfs_create_inode(name, mode, vfs_root()); } else { *ebx = -1; return; } } else { if(oflags & O_EXCL) { *ebx = -1; return; } } if(oflags & O_TRUNC) { memclr(inode->base, inode->length); } current_proc->fd[fd]->inode = inode; current_proc->fd[fd]->flags = oflags; current_proc->fd[fd]->mode = mode; current_proc->fd[fd]->pos = 0; *ebx = fd; }
int devtmpfs_delete_node(struct device *dev) { const char *tmp = NULL; const char *nodename; const struct cred *curr_cred; struct nameidata nd; struct dentry *dentry; struct kstat stat; int deleted = 1; int err; if (!dev_mnt) return 0; nodename = device_get_devnode(dev, NULL, &tmp); if (!nodename) return -ENOMEM; curr_cred = override_creds(&init_cred); err = vfs_path_lookup(dev_mnt->mnt_root, dev_mnt, nodename, LOOKUP_PARENT, &nd); if (err) goto out; mutex_lock_nested(&nd.path.dentry->d_inode->i_mutex, I_MUTEX_PARENT); dentry = lookup_one_len(nd.last.name, nd.path.dentry, nd.last.len); if (!IS_ERR(dentry)) { if (dentry->d_inode) { err = vfs_getattr(nd.path.mnt, dentry, &stat); if (!err && dev_mynode(dev, dentry->d_inode, &stat)) { struct iattr newattrs; /* * before unlinking this node, reset permissions * of possible references like hardlinks */ newattrs.ia_uid = 0; newattrs.ia_gid = 0; newattrs.ia_mode = stat.mode & ~0777; newattrs.ia_valid = ATTR_UID|ATTR_GID|ATTR_MODE; mutex_lock(&dentry->d_inode->i_mutex); notify_change(dentry, &newattrs); mutex_unlock(&dentry->d_inode->i_mutex); err = vfs_unlink(nd.path.dentry->d_inode, dentry); if (!err || err == -ENOENT) deleted = 1; } } else { err = -ENOENT; } dput(dentry); } else { err = PTR_ERR(dentry); } mutex_unlock(&nd.path.dentry->d_inode->i_mutex); path_put(&nd.path); if (deleted && strchr(nodename, '/')) delete_path(nodename); out: kfree(tmp); revert_creds(curr_cred); return err; }
int devtmpfs_create_node(struct device *dev) { const char *tmp = NULL; const char *nodename; const struct cred *curr_cred; mode_t mode = 0; struct nameidata nd; struct dentry *dentry; int err; if (!dev_mnt) return 0; nodename = device_get_devnode(dev, &mode, &tmp); if (!nodename) return -ENOMEM; if (mode == 0) mode = 0600; if (is_blockdev(dev)) mode |= S_IFBLK; else mode |= S_IFCHR; curr_cred = override_creds(&init_cred); err = vfs_path_lookup(dev_mnt->mnt_root, dev_mnt, nodename, LOOKUP_PARENT, &nd); if (err == -ENOENT) { create_path(nodename); err = vfs_path_lookup(dev_mnt->mnt_root, dev_mnt, nodename, LOOKUP_PARENT, &nd); } if (err) goto out; dentry = lookup_create(&nd, 0); if (!IS_ERR(dentry)) { err = vfs_mknod(nd.path.dentry->d_inode, dentry, mode, dev->devt); if (!err) { struct iattr newattrs; /* fixup possibly umasked mode */ newattrs.ia_mode = mode; newattrs.ia_valid = ATTR_MODE; mutex_lock(&dentry->d_inode->i_mutex); notify_change(dentry, &newattrs); mutex_unlock(&dentry->d_inode->i_mutex); /* mark as kernel-created inode */ dentry->d_inode->i_private = &dev_mnt; } dput(dentry); } else { err = PTR_ERR(dentry); } mutex_unlock(&nd.path.dentry->d_inode->i_mutex); path_put(&nd.path); out: kfree(tmp); revert_creds(curr_cred); return err; }
/* * Main driver function for sdcardfs's lookup. * * Returns: NULL (ok), ERR_PTR if an error occurred. * Fills in lower_parent_path with <dentry,mnt> on success. */ static struct dentry *__sdcardfs_lookup(struct dentry *dentry, struct nameidata *nd, struct path *lower_parent_path) { int err = 0; struct vfsmount *lower_dir_mnt; struct dentry *lower_dir_dentry = NULL; struct dentry *lower_dentry; const char *name; struct path lower_path; struct qstr this; /* must initialize dentry operations */ d_set_d_op(dentry, &sdcardfs_dops); if (IS_ROOT(dentry)) goto out; name = dentry->d_name.name; /* now start the actual lookup procedure */ lower_dir_dentry = lower_parent_path->dentry; lower_dir_mnt = lower_parent_path->mnt; /* Use vfs_path_lookup to check if the dentry exists or not */ err = vfs_path_lookup(lower_dir_dentry, lower_dir_mnt, name, 0, &lower_path); /* no error: handle positive dentries */ if (!err) { #ifdef SDCARDFS_CASE_INSENSITIVE_MATCH_SUPPORT dentry_found: #endif sdcardfs_set_lower_path(dentry, &lower_path); err = sdcardfs_interpose(dentry, dentry->d_sb, &lower_path); if (err) /* path_put underlying path on error */ sdcardfs_put_reset_lower_path(dentry); goto out; } #ifdef SDCARDFS_CASE_INSENSITIVE_MATCH_SUPPORT if (err == -ENOENT) { /* try case insensetive match */ char * match_name = NULL; match_name = find_case_insensitive(lower_parent_path, name); if (unlikely(IS_ERR(match_name))) { err = PTR_ERR(match_name); } else if (match_name) { /* found */ err = vfs_path_lookup(lower_dir_dentry, lower_dir_mnt, match_name, 0, &lower_path); kfree(match_name); if (!err) goto dentry_found; } /* no match */ } #endif /* * We don't consider ENOENT an error, and we want to return a * negative dentry. */ if (err && err != -ENOENT) goto out; /* instatiate a new negative dentry */ this.name = name; this.len = strlen(name); this.hash = full_name_hash(this.name, this.len); lower_dentry = d_lookup(lower_dir_dentry, &this); if (lower_dentry) goto setup_lower; lower_dentry = d_alloc(lower_dir_dentry, &this); if (!lower_dentry) { err = -ENOMEM; goto out; } d_add(lower_dentry, NULL); /* instantiate and hash */ setup_lower: lower_path.dentry = lower_dentry; lower_path.mnt = mntget(lower_dir_mnt); sdcardfs_set_lower_path(dentry, &lower_path); /* * If the intent is to create a file, then don't return an error, so * the VFS will continue the process of making this negative dentry * into a positive one. */ if (nd) { if (nd->flags & (LOOKUP_CREATE|LOOKUP_RENAME_TARGET)) err = 0; } else err = 0; out: return ERR_PTR(err); }
/* * Safely creates '/proc/systemtap' (if necessary) and * '/proc/systemtap/{module_name}'. * * NB: this function is suitable to call from early in the the * module-init function, and doesn't rely on any other facilities * in our runtime. PR19833. See also PR15408. */ static int _stp_mkdir_proc_module(void) { int found = 0; static char proc_root_name[STP_MODULE_NAME_LEN + sizeof("systemtap/")]; #if defined(STAPCONF_PATH_LOOKUP) || defined(STAPCONF_KERN_PATH_PARENT) struct nameidata nd; #else /* STAPCONF_VFS_PATH_LOOKUP or STAPCONF_KERN_PATH */ struct path path; #if defined(STAPCONF_VFS_PATH_LOOKUP) struct vfsmount *mnt; #endif int rc; #endif /* STAPCONF_VFS_PATH_LOOKUP or STAPCONF_KERN_PATH */ if (_stp_proc_root != NULL) return 0; #if defined(STAPCONF_PATH_LOOKUP) || defined(STAPCONF_KERN_PATH_PARENT) /* Why "/proc/systemtap/foo"? kern_path_parent() is basically * the same thing as calling the old path_lookup() with flags * set to LOOKUP_PARENT, which means to look up the parent of * the path, which in this case is "/proc/systemtap". */ if (! kern_path_parent("/proc/systemtap/foo", &nd)) { found = 1; #ifdef STAPCONF_NAMEIDATA_CLEANUP path_put(&nd.path); #else /* !STAPCONF_NAMEIDATA_CLEANUP */ path_release(&nd); #endif /* !STAPCONF_NAMEIDATA_CLEANUP */ } #elif defined(STAPCONF_KERN_PATH) /* Prefer kern_path() over vfs_path_lookup(), since on some * kernels the declaration for vfs_path_lookup() was moved to * a private header. */ /* See if '/proc/systemtap' exists. */ rc = kern_path("/proc/systemtap", 0, &path); if (rc == 0) { found = 1; path_put (&path); } #else /* STAPCONF_VFS_PATH_LOOKUP */ /* See if '/proc/systemtap' exists. */ if (! init_pid_ns.proc_mnt) { errk("Unable to create '/proc/systemap':" " '/proc' doesn't exist.\n"); goto done; } mnt = init_pid_ns.proc_mnt; rc = vfs_path_lookup(mnt->mnt_root, mnt, "systemtap", 0, &path); if (rc == 0) { found = 1; path_put (&path); } #endif /* STAPCONF_VFS_PATH_LOOKUP */ /* If we couldn't find "/proc/systemtap", create it. */ if (!found) { struct proc_dir_entry *de; de = proc_mkdir ("systemtap", NULL); if (de == NULL) { errk("Unable to create '/proc/systemap':" " proc_mkdir failed.\n"); goto done; } } /* Create the "systemtap/{module_name} directory in procfs. */ strlcpy(proc_root_name, "systemtap/", sizeof(proc_root_name)); strlcat(proc_root_name, THIS_MODULE->name, sizeof(proc_root_name)); _stp_proc_root = proc_mkdir(proc_root_name, NULL); #ifdef STAPCONF_PROCFS_OWNER if (_stp_proc_root != NULL) _stp_proc_root->owner = THIS_MODULE; #endif if (_stp_proc_root == NULL) errk("Unable to create '/proc/systemap/%s':" " proc_mkdir failed.\n", THIS_MODULE->name); done: return (_stp_proc_root) ? 0 : -EINVAL; }
/* * Main driver function for sdcardfskk's lookup. * * Returns: NULL (ok), ERR_PTR if an error occurred. * Fills in lower_parent_path with <dentry,mnt> on success. */ static struct dentry *__sdcardfskk_lookup(struct dentry *dentry, struct nameidata *nd, struct path *lower_parent_path) { int err = 0; struct vfsmount *lower_dir_mnt; struct dentry *lower_dir_dentry = NULL; struct dentry *lower_dentry; const char *name; struct nameidata lower_nd; struct path lower_path; struct qstr this; struct sdcardfskk_sb_info *sbi; sbi = SDCARDFSKK_SB(dentry->d_sb); /* must initialize dentry operations */ d_set_d_op(dentry, &sdcardfskk_ci_dops); if (IS_ROOT(dentry)) goto out; name = dentry->d_name.name; /* now start the actual lookup procedure */ lower_dir_dentry = lower_parent_path->dentry; lower_dir_mnt = lower_parent_path->mnt; /* Use vfs_path_lookup to check if the dentry exists or not */ if (sbi->options.lower_fs == LOWER_FS_EXT4) { err = vfs_path_lookup(lower_dir_dentry, lower_dir_mnt, name, LOOKUP_CASE_INSENSITIVE, &lower_nd); } else if (sbi->options.lower_fs == LOWER_FS_FAT) { err = vfs_path_lookup(lower_dir_dentry, lower_dir_mnt, name, 0, &lower_nd); } /* no error: handle positive dentries */ if (!err) { /* check if the dentry is an obb dentry * if true, the lower_inode must be replaced with * the inode of the graft path */ if(need_graft_path_kitkat(dentry)) { /* setup_obb_dentry_kitkat() * The lower_path will be stored to the dentry's orig_path * and the base obbpath will be copyed to the lower_path variable. * if an error returned, there's no change in the lower_path * returns: -ERRNO if error (0: no error) */ err = setup_obb_dentry_kitkat(dentry, &lower_nd.path); if(err) { /* if the sbi->obbpath is not available, we can optionally * setup the lower_path with its orig_path. * but, the current implementation just returns an error * because the sdcard daemon also regards this case as * a lookup fail. */ printk(KERN_INFO "sdcardfskk: base obbpath is not available\n"); sdcardfskk_put_reset_orig_path(dentry); goto out; } } sdcardfskk_set_lower_path(dentry, &lower_nd.path); err = sdcardfskk_interpose(dentry, dentry->d_sb, &lower_nd.path); if (err) /* path_put underlying path on error */ sdcardfskk_put_reset_lower_path(dentry); goto out; } /* * We don't consider ENOENT an error, and we want to return a * negative dentry. */ if (err && err != -ENOENT) goto out; /* instatiate a new negative dentry */ this.name = name; this.len = strlen(name); this.hash = full_name_hash(this.name, this.len); lower_dentry = d_lookup(lower_dir_dentry, &this); if (lower_dentry) goto setup_lower; lower_dentry = d_alloc(lower_dir_dentry, &this); if (!lower_dentry) { err = -ENOMEM; goto out; } d_add(lower_dentry, NULL); /* instantiate and hash */ setup_lower: lower_path.dentry = lower_dentry; lower_path.mnt = mntget(lower_dir_mnt); sdcardfskk_set_lower_path(dentry, &lower_path); /* * If the intent is to create a file, then don't return an error, so * the VFS will continue the process of making this negative dentry * into a positive one. */ if (nd) { if (nd->flags & (LOOKUP_CREATE|LOOKUP_RENAME_TARGET)) err = 0; } else err = 0; out: return ERR_PTR(err); }
/* * Main driver function for wrapfs's lookup. * * Returns: NULL (ok), ERR_PTR if an error occurred. * Fills in lower_parent_path with <dentry,mnt> on success. */ static struct dentry *__wrapfs_lookup(struct dentry *dentry, int flags, struct path *lower_parent_path) { int err = 0; struct vfsmount *lower_dir_mnt; struct dentry *lower_dir_dentry = NULL; struct dentry *lower_dentry; const char *name; struct path lower_path; struct qstr this; /* must initialize dentry operations */ d_set_d_op(dentry, &wrapfs_dops); if (IS_ROOT(dentry)) goto out; name = dentry->d_name.name; /* now start the actual lookup procedure */ lower_dir_dentry = lower_parent_path->dentry; lower_dir_mnt = lower_parent_path->mnt; /* Use vfs_path_lookup to check if the dentry exists or not */ err = vfs_path_lookup(lower_dir_dentry, lower_dir_mnt, name, 0, &lower_path); /* no error: handle positive dentries */ if (!err) { wrapfs_set_lower_path(dentry, &lower_path); err = wrapfs_interpose(dentry, dentry->d_sb, &lower_path); if (err) /* path_put underlying path on error */ wrapfs_put_reset_lower_path(dentry); goto out; } /* * We don't consider ENOENT an error, and we want to return a * negative dentry. */ if (err && err != -ENOENT) goto out; /* instatiate a new negative dentry */ this.name = name; this.len = strlen(name); this.hash = full_name_hash(this.name, this.len); lower_dentry = d_lookup(lower_dir_dentry, &this); if (lower_dentry) goto setup_lower; lower_dentry = d_alloc(lower_dir_dentry, &this); if (!lower_dentry) { err = -ENOMEM; goto out; } d_add(lower_dentry, NULL); /* instantiate and hash */ setup_lower: lower_path.dentry = lower_dentry; lower_path.mnt = mntget(lower_dir_mnt); wrapfs_set_lower_path(dentry, &lower_path); /* * If the intent is to create a file, then don't return an error, so * the VFS will continue the process of making this negative dentry * into a positive one. */ if (flags & (LOOKUP_CREATE|LOOKUP_RENAME_TARGET)) err = 0; out: return ERR_PTR(err); }
int devtmpfs_create_node(struct device *dev) { const char *tmp = NULL; const char *nodename; const struct cred *curr_cred; struct user_beancounter *curr_ub; mode_t mode = 0; struct nameidata nd; struct dentry *dentry; int err; struct vfsmount *dev_mnt = ve_devmnt(); if (!dev_mnt) return 0; nodename = device_get_devnode(dev, &mode, &tmp); if (!nodename) return -ENOMEM; if (mode == 0) mode = 0600; if (is_blockdev(dev)) mode |= S_IFBLK; else mode |= S_IFCHR; curr_ub = set_exec_ub(&ub0); curr_cred = override_creds(&init_cred); err = vfs_path_lookup(dev_mnt->mnt_root, dev_mnt, nodename, LOOKUP_PARENT, &nd); if (err == -ENOENT) { /* create missing parent directories */ create_path(nodename); err = vfs_path_lookup(dev_mnt->mnt_root, dev_mnt, nodename, LOOKUP_PARENT, &nd); if (err) goto out; } dentry = lookup_create(&nd, 0); if (!IS_ERR(dentry)) { int umask; umask = sys_umask(0000); err = vfs_mknod(nd.path.dentry->d_inode, dentry, mode, dev->devt); sys_umask(umask); /* mark as kernel created inode */ if (!err) dentry->d_inode->i_private = &dev_mnt; dput(dentry); } else { err = PTR_ERR(dentry); } mutex_unlock(&nd.path.dentry->d_inode->i_mutex); path_put(&nd.path); out: kfree(tmp); revert_creds(curr_cred); (void)set_exec_ub(curr_ub); return err; }