Merge tag 'vfs-6.16-rc1.async.dir' of git://git.kernel.org/pub/scm/linux/kernel/git/vfs/vfs

Pull vfs directory lookup updates from Christian Brauner:
 "This contains cleanups for the lookup_one*() family of helpers.

  We expose a set of functions with names containing "lookup_one_len"
  and others without the "_len". This difference has nothing to do with
  "len". It's rater a historical accident that can be confusing.

  The functions without "_len" take a "mnt_idmap" pointer. This is found
  in the "vfsmount" and that is an important question when choosing
  which to use: do you have a vfsmount, or are you "inside" the
  filesystem. A related question is "is permission checking relevant
  here?".

  nfsd and cachefiles *do* have a vfsmount but *don't* use the non-_len
  functions. They pass nop_mnt_idmap and refuse to work on filesystems
  which have any other idmap.

  This work changes nfsd and cachefile to use the lookup_one family of
  functions and to explictily pass &nop_mnt_idmap which is consistent
  with all other vfs interfaces used where &nop_mnt_idmap is explicitly
  passed.

  The remaining uses of the "_one" functions do not require permission
  checks so these are renamed to be "_noperm" and the permission
  checking is removed.

  This series also changes these lookup function to take a qstr instead
  of separate name and len. In many cases this simplifies the call"

* tag 'vfs-6.16-rc1.async.dir' of git://git.kernel.org/pub/scm/linux/kernel/git/vfs/vfs:
  VFS: change lookup_one_common and lookup_noperm_common to take a qstr
  Use try_lookup_noperm() instead of d_hash_and_lookup() outside of VFS
  VFS: rename lookup_one_len family to lookup_noperm and remove permission check
  cachefiles: Use lookup_one() rather than lookup_one_len()
  nfsd: Use lookup_one() rather than lookup_one_len()
  VFS: improve interface for lookup_one functions
This commit is contained in:
Linus Torvalds
2025-05-26 08:02:43 -07:00
48 changed files with 254 additions and 210 deletions
+40
View File
@@ -1203,3 +1203,43 @@ should use d_drop();d_splice_alias() and return the result of the latter.
If a positive dentry cannot be returned for some reason, in-kernel
clients such as cachefiles, nfsd, smb/server may not perform ideally but
will fail-safe.
---
** mandatory**
lookup_one(), lookup_one_unlocked(), lookup_one_positive_unlocked() now
take a qstr instead of a name and len. These, not the "one_len"
versions, should be used whenever accessing a filesystem from outside
that filesysmtem, through a mount point - which will have a mnt_idmap.
---
** mandatory**
Functions try_lookup_one_len(), lookup_one_len(),
lookup_one_len_unlocked() and lookup_positive_unlocked() have been
renamed to try_lookup_noperm(), lookup_noperm(),
lookup_noperm_unlocked(), lookup_noperm_positive_unlocked(). They now
take a qstr instead of separate name and length. QSTR() can be used
when strlen() is needed for the length.
For try_lookup_noperm() a reference to the qstr is passed in case the
hash might subsequently be needed.
These function no longer do any permission checking - they previously
checked that the caller has 'X' permission on the parent. They must
ONLY be used internally by a filesystem on itself when it knows that
permissions are irrelevant or in a context where permission checks have
already been performed such as after vfs_path_parent_lookup()
---
** mandatory**
d_hash_and_lookup() is no longer exported or available outside the VFS.
Use try_lookup_noperm() instead. This adds name validation and takes
arguments in the opposite order but is otherwise identical.
Using try_lookup_noperm() will require linux/namei.h to be included.
+1 -1
View File
@@ -342,7 +342,7 @@ static struct dentry *hypfs_create_file(struct dentry *parent, const char *name,
struct inode *inode;
inode_lock(d_inode(parent));
dentry = lookup_one_len(name, parent, strlen(name));
dentry = lookup_noperm(&QSTR(name), parent);
if (IS_ERR(dentry)) {
dentry = ERR_PTR(-ENOMEM);
goto fail;
+2 -2
View File
@@ -187,7 +187,7 @@ static int binderfs_binder_device_create(struct inode *ref_inode,
inode_lock(d_inode(root));
/* look it up */
dentry = lookup_one_len(name, root, name_len);
dentry = lookup_noperm(&QSTR(name), root);
if (IS_ERR(dentry)) {
inode_unlock(d_inode(root));
ret = PTR_ERR(dentry);
@@ -487,7 +487,7 @@ static struct dentry *binderfs_create_dentry(struct dentry *parent,
{
struct dentry *dentry;
dentry = lookup_one_len(name, parent, strlen(name));
dentry = lookup_noperm(&QSTR(name), parent);
if (IS_ERR(dentry))
return dentry;
+2 -2
View File
@@ -90,7 +90,7 @@ static int create_file(const char *name, umode_t mode,
int error;
inode_lock(d_inode(parent));
*dentry = lookup_one_len(name, parent, strlen(name));
*dentry = lookup_noperm(&QSTR(name), parent);
if (!IS_ERR(*dentry))
error = qibfs_mknod(d_inode(parent), *dentry,
mode, fops, data);
@@ -433,7 +433,7 @@ static int remove_device_files(struct super_block *sb,
char unit[10];
snprintf(unit, sizeof(unit), "%u", dd->unit);
dir = lookup_one_len_unlocked(unit, sb->s_root, strlen(unit));
dir = lookup_noperm_unlocked(&QSTR(unit), sb->s_root);
if (IS_ERR(dir)) {
pr_err("Lookup of %s failed\n", unit);
+1 -1
View File
@@ -943,7 +943,7 @@ static struct dentry *afs_lookup_atsys(struct inode *dir, struct dentry *dentry)
}
strcpy(p, name);
ret = lookup_one_len(buf, dentry->d_parent, len);
ret = lookup_noperm(&QSTR(buf), dentry->d_parent);
if (IS_ERR(ret) || d_is_positive(ret))
goto out_s;
dput(ret);
+2 -4
View File
@@ -113,16 +113,14 @@ int afs_sillyrename(struct afs_vnode *dvnode, struct afs_vnode *vnode,
sdentry = NULL;
do {
int slen;
dput(sdentry);
sillycounter++;
/* Create a silly name. Note that the ".__afs" prefix is
* understood by the salvager and must not be changed.
*/
slen = scnprintf(silly, sizeof(silly), ".__afs%04X", sillycounter);
sdentry = lookup_one_len(silly, dentry->d_parent, slen);
scnprintf(silly, sizeof(silly), ".__afs%04X", sillycounter);
sdentry = lookup_noperm(&QSTR(silly), dentry->d_parent);
/* N.B. Better to return EBUSY here ... it could be dangerous
* to delete the file while it's in use.
+2 -1
View File
@@ -459,7 +459,8 @@ static int autofs_dev_ioctl_timeout(struct file *fp,
"the parent autofs mount timeout which could "
"prevent shutdown\n");
dentry = try_lookup_one_len(param->path, base, path_len);
dentry = try_lookup_noperm(&QSTR_LEN(param->path, path_len),
base);
if (IS_ERR_OR_NULL(dentry))
return dentry ? PTR_ERR(dentry) : -ENOENT;
ino = autofs_dentry_ino(dentry);
+1 -1
View File
@@ -842,7 +842,7 @@ static ssize_t bm_register_write(struct file *file, const char __user *buffer,
}
inode_lock(d_inode(root));
dentry = lookup_one_len(e->name, root, strlen(e->name));
dentry = lookup_noperm(&QSTR(e->name), root);
err = PTR_ERR(dentry);
if (IS_ERR(dentry))
goto out;
+3 -6
View File
@@ -909,7 +909,7 @@ static noinline int btrfs_mksubvol(const struct path *parent,
if (error == -EINTR)
return error;
dentry = lookup_one(idmap, name, parent->dentry, namelen);
dentry = lookup_one(idmap, &QSTR_LEN(name, namelen), parent->dentry);
error = PTR_ERR(dentry);
if (IS_ERR(dentry))
goto out_unlock;
@@ -2288,7 +2288,6 @@ static noinline int btrfs_ioctl_snap_destroy(struct file *file,
struct btrfs_ioctl_vol_args_v2 *vol_args2 = NULL;
struct mnt_idmap *idmap = file_mnt_idmap(file);
char *subvol_name, *subvol_name_ptr = NULL;
int subvol_namelen;
int ret = 0;
bool destroy_parent = false;
@@ -2411,10 +2410,8 @@ static noinline int btrfs_ioctl_snap_destroy(struct file *file,
goto out;
}
subvol_namelen = strlen(subvol_name);
if (strchr(subvol_name, '/') ||
strncmp(subvol_name, "..", subvol_namelen) == 0) {
strcmp(subvol_name, "..") == 0) {
ret = -EINVAL;
goto free_subvol_name;
}
@@ -2427,7 +2424,7 @@ static noinline int btrfs_ioctl_snap_destroy(struct file *file,
ret = down_write_killable_nested(&dir->i_rwsem, I_MUTEX_PARENT);
if (ret == -EINTR)
goto free_subvol_name;
dentry = lookup_one(idmap, subvol_name, parent, subvol_namelen);
dentry = lookup_one(idmap, &QSTR(subvol_name), parent);
if (IS_ERR(dentry)) {
ret = PTR_ERR(dentry);
goto out_unlock_dir;
-1
View File
@@ -71,7 +71,6 @@ struct cachefiles_object {
int debug_id;
spinlock_t lock;
refcount_t ref;
u8 d_name_len; /* Length of filename */
enum cachefiles_content content_info:8; /* Info about content presence */
unsigned long flags;
#define CACHEFILES_OBJECT_USING_TMPFILE 0 /* Have an unlinked tmpfile */
-1
View File
@@ -132,7 +132,6 @@ bool cachefiles_cook_key(struct cachefiles_object *object)
success:
name[len] = 0;
object->d_name = name;
object->d_name_len = len;
_leave(" = %s", object->d_name);
return true;
}
+7 -7
View File
@@ -98,7 +98,7 @@ struct dentry *cachefiles_get_directory(struct cachefiles_cache *cache,
retry:
ret = cachefiles_inject_read_error();
if (ret == 0)
subdir = lookup_one_len(dirname, dir, strlen(dirname));
subdir = lookup_one(&nop_mnt_idmap, &QSTR(dirname), dir);
else
subdir = ERR_PTR(ret);
trace_cachefiles_lookup(NULL, dir, subdir);
@@ -338,7 +338,7 @@ try_again:
return -EIO;
}
grave = lookup_one_len(nbuffer, cache->graveyard, strlen(nbuffer));
grave = lookup_one(&nop_mnt_idmap, &QSTR(nbuffer), cache->graveyard);
if (IS_ERR(grave)) {
unlock_rename(cache->graveyard, dir);
trace_cachefiles_vfs_error(object, d_inode(cache->graveyard),
@@ -630,8 +630,8 @@ bool cachefiles_look_up_object(struct cachefiles_object *object)
/* Look up path "cache/vol/fanout/file". */
ret = cachefiles_inject_read_error();
if (ret == 0)
dentry = lookup_positive_unlocked(object->d_name, fan,
object->d_name_len);
dentry = lookup_one_positive_unlocked(&nop_mnt_idmap,
&QSTR(object->d_name), fan);
else
dentry = ERR_PTR(ret);
trace_cachefiles_lookup(object, fan, dentry);
@@ -683,7 +683,7 @@ bool cachefiles_commit_tmpfile(struct cachefiles_cache *cache,
inode_lock_nested(d_inode(fan), I_MUTEX_PARENT);
ret = cachefiles_inject_read_error();
if (ret == 0)
dentry = lookup_one_len(object->d_name, fan, object->d_name_len);
dentry = lookup_one(&nop_mnt_idmap, &QSTR(object->d_name), fan);
else
dentry = ERR_PTR(ret);
if (IS_ERR(dentry)) {
@@ -702,7 +702,7 @@ bool cachefiles_commit_tmpfile(struct cachefiles_cache *cache,
dput(dentry);
ret = cachefiles_inject_read_error();
if (ret == 0)
dentry = lookup_one_len(object->d_name, fan, object->d_name_len);
dentry = lookup_one(&nop_mnt_idmap, &QSTR(object->d_name), fan);
else
dentry = ERR_PTR(ret);
if (IS_ERR(dentry)) {
@@ -751,7 +751,7 @@ static struct dentry *cachefiles_lookup_for_cull(struct cachefiles_cache *cache,
inode_lock_nested(d_inode(dir), I_MUTEX_PARENT);
victim = lookup_one_len(filename, dir, strlen(filename));
victim = lookup_one(&nop_mnt_idmap, &QSTR(filename), dir);
if (IS_ERR(victim))
goto lookup_error;
if (d_is_negative(victim))
-1
View File
@@ -2412,7 +2412,6 @@ struct dentry *d_hash_and_lookup(struct dentry *dir, struct qstr *name)
}
return d_lookup(dir, name);
}
EXPORT_SYMBOL(d_hash_and_lookup);
/*
* When a file is deleted, we have two options:
+3 -3
View File
@@ -346,7 +346,7 @@ struct dentry *debugfs_lookup(const char *name, struct dentry *parent)
if (!parent)
parent = debugfs_mount->mnt_root;
dentry = lookup_positive_unlocked(name, parent, strlen(name));
dentry = lookup_noperm_positive_unlocked(&QSTR(name), parent);
if (IS_ERR(dentry))
return NULL;
return dentry;
@@ -388,7 +388,7 @@ static struct dentry *start_creating(const char *name, struct dentry *parent)
if (unlikely(IS_DEADDIR(d_inode(parent))))
dentry = ERR_PTR(-ENOENT);
else
dentry = lookup_one_len(name, parent, strlen(name));
dentry = lookup_noperm(&QSTR(name), parent);
if (!IS_ERR(dentry) && d_really_is_positive(dentry)) {
if (d_is_dir(dentry))
pr_err("Directory '%s' with parent '%s' already present!\n",
@@ -872,7 +872,7 @@ int __printf(2, 3) debugfs_change_name(struct dentry *dentry, const char *fmt, .
}
if (strcmp(old_name.name.name, new_name) == 0)
goto out;
target = lookup_one_len(new_name, parent, strlen(new_name));
target = lookup_noperm(&QSTR(new_name), parent);
if (IS_ERR(target)) {
error = PTR_ERR(target);
goto out;
+9 -7
View File
@@ -394,8 +394,8 @@ static struct dentry *ecryptfs_lookup(struct inode *ecryptfs_dir_inode,
char *encrypted_and_encoded_name = NULL;
struct ecryptfs_mount_crypt_stat *mount_crypt_stat;
struct dentry *lower_dir_dentry, *lower_dentry;
const char *name = ecryptfs_dentry->d_name.name;
size_t len = ecryptfs_dentry->d_name.len;
struct qstr qname = QSTR_INIT(ecryptfs_dentry->d_name.name,
ecryptfs_dentry->d_name.len);
struct dentry *res;
int rc = 0;
@@ -404,23 +404,25 @@ static struct dentry *ecryptfs_lookup(struct inode *ecryptfs_dir_inode,
mount_crypt_stat = &ecryptfs_superblock_to_private(
ecryptfs_dentry->d_sb)->mount_crypt_stat;
if (mount_crypt_stat->flags & ECRYPTFS_GLOBAL_ENCRYPT_FILENAMES) {
size_t len = qname.len;
rc = ecryptfs_encrypt_and_encode_filename(
&encrypted_and_encoded_name, &len,
mount_crypt_stat, name, len);
mount_crypt_stat, qname.name, len);
if (rc) {
printk(KERN_ERR "%s: Error attempting to encrypt and encode "
"filename; rc = [%d]\n", __func__, rc);
return ERR_PTR(rc);
}
name = encrypted_and_encoded_name;
qname.name = encrypted_and_encoded_name;
qname.len = len;
}
lower_dentry = lookup_one_len_unlocked(name, lower_dir_dentry, len);
lower_dentry = lookup_noperm_unlocked(&qname, lower_dir_dentry);
if (IS_ERR(lower_dentry)) {
ecryptfs_printk(KERN_DEBUG, "%s: lookup_one_len() returned "
ecryptfs_printk(KERN_DEBUG, "%s: lookup_noperm() returned "
"[%ld] on lower_dentry = [%s]\n", __func__,
PTR_ERR(lower_dentry),
name);
qname.name);
res = ERR_CAST(lower_dentry);
} else {
res = ecryptfs_lookup_interpose(ecryptfs_dentry, lower_dentry);
+5 -10
View File
@@ -18,6 +18,7 @@
#include <linux/statfs.h>
#include <linux/notifier.h>
#include <linux/printk.h>
#include <linux/namei.h>
#include "internal.h"
@@ -204,7 +205,6 @@ bool efivarfs_variable_is_present(efi_char16_t *variable_name,
char *name = efivar_get_utf8name(variable_name, vendor);
struct super_block *sb = data;
struct dentry *dentry;
struct qstr qstr;
if (!name)
/*
@@ -217,9 +217,7 @@ bool efivarfs_variable_is_present(efi_char16_t *variable_name,
*/
return true;
qstr.name = name;
qstr.len = strlen(name);
dentry = d_hash_and_lookup(sb->s_root, &qstr);
dentry = try_lookup_noperm(&QSTR(name), sb->s_root);
kfree(name);
if (!IS_ERR_OR_NULL(dentry))
dput(dentry);
@@ -404,8 +402,8 @@ static bool efivarfs_actor(struct dir_context *ctx, const char *name, int len,
{
unsigned long size;
struct efivarfs_ctx *ectx = container_of(ctx, struct efivarfs_ctx, ctx);
struct qstr qstr = { .name = name, .len = len };
struct dentry *dentry = d_hash_and_lookup(ectx->sb->s_root, &qstr);
struct dentry *dentry = try_lookup_noperm(&QSTR_LEN(name, len),
ectx->sb->s_root);
struct inode *inode;
struct efivar_entry *entry;
int err;
@@ -441,7 +439,6 @@ static int efivarfs_check_missing(efi_char16_t *name16, efi_guid_t vendor,
char *name;
struct super_block *sb = data;
struct dentry *dentry;
struct qstr qstr;
int err;
if (guid_equal(&vendor, &LINUX_EFI_RANDOM_SEED_TABLE_GUID))
@@ -451,9 +448,7 @@ static int efivarfs_check_missing(efi_char16_t *name16, efi_guid_t vendor,
if (!name)
return -ENOMEM;
qstr.name = name;
qstr.len = strlen(name);
dentry = d_hash_and_lookup(sb->s_root, &qstr);
dentry = try_lookup_noperm(&QSTR(name), sb->s_root);
if (IS_ERR(dentry)) {
err = PTR_ERR(dentry);
goto out;
+2 -3
View File
@@ -143,7 +143,7 @@ static struct dentry *reconnect_one(struct vfsmount *mnt,
if (err)
goto out_err;
dprintk("%s: found name: %s\n", __func__, nbuf);
tmp = lookup_one_unlocked(mnt_idmap(mnt), nbuf, parent, strlen(nbuf));
tmp = lookup_one_unlocked(mnt_idmap(mnt), &QSTR(nbuf), parent);
if (IS_ERR(tmp)) {
dprintk("lookup failed: %ld\n", PTR_ERR(tmp));
err = PTR_ERR(tmp);
@@ -549,8 +549,7 @@ exportfs_decode_fh_raw(struct vfsmount *mnt, struct fid *fid, int fh_len,
}
inode_lock(target_dir->d_inode);
nresult = lookup_one(mnt_idmap(mnt), nbuf,
target_dir, strlen(nbuf));
nresult = lookup_one(mnt_idmap(mnt), &QSTR(nbuf), target_dir);
if (!IS_ERR(nresult)) {
if (unlikely(nresult->d_inode != result->d_inode)) {
dput(nresult);
+1
View File
@@ -66,6 +66,7 @@ int do_linkat(int olddfd, struct filename *old, int newdfd,
int vfs_tmpfile(struct mnt_idmap *idmap,
const struct path *parentpath,
struct file *file, umode_t mode);
struct dentry *d_hash_and_lookup(struct dentry *, struct qstr *);
/*
* namespace.c
+1 -1
View File
@@ -255,7 +255,7 @@ struct dentry *kernfs_node_dentry(struct kernfs_node *kn,
dput(dentry);
return ERR_PTR(-ENOMEM);
}
dtmp = lookup_positive_unlocked(name, dentry, strlen(name));
dtmp = lookup_noperm_positive_unlocked(&QSTR(name), dentry);
dput(dentry);
kfree(name);
if (IS_ERR(dtmp))
+80 -76
View File
@@ -2869,13 +2869,12 @@ int vfs_path_lookup(struct dentry *dentry, struct vfsmount *mnt,
}
EXPORT_SYMBOL(vfs_path_lookup);
static int lookup_one_common(struct mnt_idmap *idmap,
const char *name, struct dentry *base, int len,
struct qstr *this)
static int lookup_noperm_common(struct qstr *qname, struct dentry *base)
{
this->name = name;
this->len = len;
this->hash = full_name_hash(base, name, len);
const char *name = qname->name;
u32 len = qname->len;
qname->hash = full_name_hash(base, name, len);
if (!len)
return -EACCES;
@@ -2892,139 +2891,135 @@ static int lookup_one_common(struct mnt_idmap *idmap,
* to use its own hash..
*/
if (base->d_flags & DCACHE_OP_HASH) {
int err = base->d_op->d_hash(base, this);
int err = base->d_op->d_hash(base, qname);
if (err < 0)
return err;
}
return 0;
}
static int lookup_one_common(struct mnt_idmap *idmap,
struct qstr *qname, struct dentry *base)
{
int err;
err = lookup_noperm_common(qname, base);
if (err < 0)
return err;
return inode_permission(idmap, base->d_inode, MAY_EXEC);
}
/**
* try_lookup_one_len - filesystem helper to lookup single pathname component
* @name: pathname component to lookup
* try_lookup_noperm - filesystem helper to lookup single pathname component
* @name: qstr storing pathname component to lookup
* @base: base directory to lookup from
* @len: maximum length @len should be interpreted to
*
* Look up a dentry by name in the dcache, returning NULL if it does not
* currently exist. The function does not try to create a dentry.
*
* Note that this routine is purely a helper for filesystem usage and should
* not be called by generic code.
* not be called by generic code. It does no permission checking.
*
* No locks need be held - only a counted reference to @base is needed.
*
*/
struct dentry *try_lookup_one_len(const char *name, struct dentry *base, int len)
struct dentry *try_lookup_noperm(struct qstr *name, struct dentry *base)
{
struct qstr this;
int err;
err = lookup_one_common(&nop_mnt_idmap, name, base, len, &this);
err = lookup_noperm_common(name, base);
if (err)
return ERR_PTR(err);
return lookup_dcache(&this, base, 0);
return lookup_dcache(name, base, 0);
}
EXPORT_SYMBOL(try_lookup_one_len);
EXPORT_SYMBOL(try_lookup_noperm);
/**
* lookup_one_len - filesystem helper to lookup single pathname component
* @name: pathname component to lookup
* lookup_noperm - filesystem helper to lookup single pathname component
* @name: qstr storing pathname component to lookup
* @base: base directory to lookup from
* @len: maximum length @len should be interpreted to
*
* Note that this routine is purely a helper for filesystem usage and should
* not be called by generic code.
* not be called by generic code. It does no permission checking.
*
* The caller must hold base->i_mutex.
*/
struct dentry *lookup_one_len(const char *name, struct dentry *base, int len)
struct dentry *lookup_noperm(struct qstr *name, struct dentry *base)
{
struct dentry *dentry;
struct qstr this;
int err;
WARN_ON_ONCE(!inode_is_locked(base->d_inode));
err = lookup_one_common(&nop_mnt_idmap, name, base, len, &this);
err = lookup_noperm_common(name, base);
if (err)
return ERR_PTR(err);
dentry = lookup_dcache(&this, base, 0);
return dentry ? dentry : __lookup_slow(&this, base, 0);
dentry = lookup_dcache(name, base, 0);
return dentry ? dentry : __lookup_slow(name, base, 0);
}
EXPORT_SYMBOL(lookup_one_len);
EXPORT_SYMBOL(lookup_noperm);
/**
* lookup_one - filesystem helper to lookup single pathname component
* lookup_one - lookup single pathname component
* @idmap: idmap of the mount the lookup is performed from
* @name: pathname component to lookup
* @name: qstr holding pathname component to lookup
* @base: base directory to lookup from
* @len: maximum length @len should be interpreted to
*
* Note that this routine is purely a helper for filesystem usage and should
* not be called by generic code.
* This can be used for in-kernel filesystem clients such as file servers.
*
* The caller must hold base->i_mutex.
*/
struct dentry *lookup_one(struct mnt_idmap *idmap, const char *name,
struct dentry *base, int len)
struct dentry *lookup_one(struct mnt_idmap *idmap, struct qstr *name,
struct dentry *base)
{
struct dentry *dentry;
struct qstr this;
int err;
WARN_ON_ONCE(!inode_is_locked(base->d_inode));
err = lookup_one_common(idmap, name, base, len, &this);
err = lookup_one_common(idmap, name, base);
if (err)
return ERR_PTR(err);
dentry = lookup_dcache(&this, base, 0);
return dentry ? dentry : __lookup_slow(&this, base, 0);
dentry = lookup_dcache(name, base, 0);
return dentry ? dentry : __lookup_slow(name, base, 0);
}
EXPORT_SYMBOL(lookup_one);
/**
* lookup_one_unlocked - filesystem helper to lookup single pathname component
* lookup_one_unlocked - lookup single pathname component
* @idmap: idmap of the mount the lookup is performed from
* @name: pathname component to lookup
* @name: qstr olding pathname component to lookup
* @base: base directory to lookup from
* @len: maximum length @len should be interpreted to
*
* Note that this routine is purely a helper for filesystem usage and should
* not be called by generic code.
* This can be used for in-kernel filesystem clients such as file servers.
*
* Unlike lookup_one_len, it should be called without the parent
* i_mutex held, and will take the i_mutex itself if necessary.
* Unlike lookup_one, it should be called without the parent
* i_rwsem held, and will take the i_rwsem itself if necessary.
*/
struct dentry *lookup_one_unlocked(struct mnt_idmap *idmap,
const char *name, struct dentry *base,
int len)
struct dentry *lookup_one_unlocked(struct mnt_idmap *idmap, struct qstr *name,
struct dentry *base)
{
struct qstr this;
int err;
struct dentry *ret;
err = lookup_one_common(idmap, name, base, len, &this);
err = lookup_one_common(idmap, name, base);
if (err)
return ERR_PTR(err);
ret = lookup_dcache(&this, base, 0);
ret = lookup_dcache(name, base, 0);
if (!ret)
ret = lookup_slow(&this, base, 0);
ret = lookup_slow(name, base, 0);
return ret;
}
EXPORT_SYMBOL(lookup_one_unlocked);
/**
* lookup_one_positive_unlocked - filesystem helper to lookup single
* pathname component
* lookup_one_positive_unlocked - lookup single pathname component
* @idmap: idmap of the mount the lookup is performed from
* @name: pathname component to lookup
* @name: qstr holding pathname component to lookup
* @base: base directory to lookup from
* @len: maximum length @len should be interpreted to
*
* This helper will yield ERR_PTR(-ENOENT) on negatives. The helper returns
* known positive or ERR_PTR(). This is what most of the users want.
@@ -3033,16 +3028,15 @@ EXPORT_SYMBOL(lookup_one_unlocked);
* time, so callers of lookup_one_unlocked() need to be very careful; pinned
* positives have >d_inode stable, so this one avoids such problems.
*
* Note that this routine is purely a helper for filesystem usage and should
* not be called by generic code.
* This can be used for in-kernel filesystem clients such as file servers.
*
* The helper should be called without i_mutex held.
* The helper should be called without i_rwsem held.
*/
struct dentry *lookup_one_positive_unlocked(struct mnt_idmap *idmap,
const char *name,
struct dentry *base, int len)
struct qstr *name,
struct dentry *base)
{
struct dentry *ret = lookup_one_unlocked(idmap, name, base, len);
struct dentry *ret = lookup_one_unlocked(idmap, name, base);
if (!IS_ERR(ret) && d_flags_negative(smp_load_acquire(&ret->d_flags))) {
dput(ret);
@@ -3053,38 +3047,48 @@ struct dentry *lookup_one_positive_unlocked(struct mnt_idmap *idmap,
EXPORT_SYMBOL(lookup_one_positive_unlocked);
/**
* lookup_one_len_unlocked - filesystem helper to lookup single pathname component
* lookup_noperm_unlocked - filesystem helper to lookup single pathname component
* @name: pathname component to lookup
* @base: base directory to lookup from
* @len: maximum length @len should be interpreted to
*
* Note that this routine is purely a helper for filesystem usage and should
* not be called by generic code.
* not be called by generic code. It does no permission checking.
*
* Unlike lookup_one_len, it should be called without the parent
* i_mutex held, and will take the i_mutex itself if necessary.
* Unlike lookup_noperm, it should be called without the parent
* i_rwsem held, and will take the i_rwsem itself if necessary.
*/
struct dentry *lookup_one_len_unlocked(const char *name,
struct dentry *base, int len)
struct dentry *lookup_noperm_unlocked(struct qstr *name, struct dentry *base)
{
return lookup_one_unlocked(&nop_mnt_idmap, name, base, len);
struct dentry *ret;
ret = try_lookup_noperm(name, base);
if (!ret)
ret = lookup_slow(name, base, 0);
return ret;
}
EXPORT_SYMBOL(lookup_one_len_unlocked);
EXPORT_SYMBOL(lookup_noperm_unlocked);
/*
* Like lookup_one_len_unlocked(), except that it yields ERR_PTR(-ENOENT)
* Like lookup_noperm_unlocked(), except that it yields ERR_PTR(-ENOENT)
* on negatives. Returns known positive or ERR_PTR(); that's what
* most of the users want. Note that pinned negative with unlocked parent
* _can_ become positive at any time, so callers of lookup_one_len_unlocked()
* _can_ become positive at any time, so callers of lookup_noperm_unlocked()
* need to be very careful; pinned positives have ->d_inode stable, so
* this one avoids such problems.
*/
struct dentry *lookup_positive_unlocked(const char *name,
struct dentry *base, int len)
struct dentry *lookup_noperm_positive_unlocked(struct qstr *name,
struct dentry *base)
{
return lookup_one_positive_unlocked(&nop_mnt_idmap, name, base, len);
struct dentry *ret;
ret = lookup_noperm_unlocked(name, base);
if (!IS_ERR(ret) && d_flags_negative(smp_load_acquire(&ret->d_flags))) {
dput(ret);
ret = ERR_PTR(-ENOENT);
}
return ret;
}
EXPORT_SYMBOL(lookup_positive_unlocked);
EXPORT_SYMBOL(lookup_noperm_positive_unlocked);
#ifdef CONFIG_UNIX98_PTYS
int path_pts(struct path *path)

Some files were not shown because too many files have changed in this diff Show More