Merge branch 'for-linus-1' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs

Pull vfs updates from Al Viro:
 "In this pile: pathname resolution rewrite.

   - recursion in link_path_walk() is gone.

   - nesting limits on symlinks are gone (the only limit remaining is
     that the total amount of symlinks is no more than 40, no matter how
     nested).

   - "fast" (inline) symlinks are handled without leaving rcuwalk mode.

   - stack footprint (independent of the nesting) is below kilobyte now,
     about on par with what it used to be with one level of nested
     symlinks and ~2.8 times lower than it used to be in the worst case.

   - struct nameidata is entirely private to fs/namei.c now (not even
     opaque pointers are being passed around).

   - ->follow_link() and ->put_link() calling conventions had been
     changed; all in-tree filesystems converted, out-of-tree should be
     able to follow reasonably easily.

     For out-of-tree conversions, see Documentation/filesystems/porting
     for details (and in-tree filesystems for examples of conversion).

  That has sat in -next since mid-May, seems to survive all testing
  without regressions and merges clean with v4.1"

* 'for-linus-1' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs: (131 commits)
  turn user_{path_at,path,lpath,path_dir}() into static inlines
  namei: move saved_nd pointer into struct nameidata
  inline user_path_create()
  inline user_path_parent()
  namei: trim do_last() arguments
  namei: stash dfd and name into nameidata
  namei: fold path_cleanup() into terminate_walk()
  namei: saner calling conventions for filename_parentat()
  namei: saner calling conventions for filename_create()
  namei: shift nameidata down into filename_parentat()
  namei: make filename_lookup() reject ERR_PTR() passed as name
  namei: shift nameidata inside filename_lookup()
  namei: move putname() call into filename_lookup()
  namei: pass the struct path to store the result down into path_lookupat()
  namei: uninline set_root{,_rcu}()
  namei: be careful with mountpoint crossings in follow_dotdot_rcu()
  Documentation: remove outdated information from automount-support.txt
  get rid of assorted nameidata-related debris
  lustre: kill unused helper
  lustre: kill unused macro (LOOKUP_CONTINUE)
  ...
This commit is contained in:
Linus Torvalds 2015-06-22 12:51:21 -07:00
commit 052b398a43
86 changed files with 1241 additions and 1541 deletions

View File

@ -50,8 +50,8 @@ prototypes:
int (*rename2) (struct inode *, struct dentry *,
struct inode *, struct dentry *, unsigned int);
int (*readlink) (struct dentry *, char __user *,int);
void * (*follow_link) (struct dentry *, struct nameidata *);
void (*put_link) (struct dentry *, struct nameidata *, void *);
const char *(*follow_link) (struct dentry *, void **);
void (*put_link) (struct inode *, void *);
void (*truncate) (struct inode *);
int (*permission) (struct inode *, int, unsigned int);
int (*get_acl)(struct inode *, int);

View File

@ -1,41 +1,15 @@
Support is available for filesystems that wish to do automounting support (such
as kAFS which can be found in fs/afs/). This facility includes allowing
in-kernel mounts to be performed and mountpoint degradation to be
requested. The latter can also be requested by userspace.
Support is available for filesystems that wish to do automounting
support (such as kAFS which can be found in fs/afs/ and NFS in
fs/nfs/). This facility includes allowing in-kernel mounts to be
performed and mountpoint degradation to be requested. The latter can
also be requested by userspace.
======================
IN-KERNEL AUTOMOUNTING
======================
A filesystem can now mount another filesystem on one of its directories by the
following procedure:
(1) Give the directory a follow_link() operation.
When the directory is accessed, the follow_link op will be called, and
it will be provided with the location of the mountpoint in the nameidata
structure (vfsmount and dentry).
(2) Have the follow_link() op do the following steps:
(a) Call vfs_kern_mount() to call the appropriate filesystem to set up a
superblock and gain a vfsmount structure representing it.
(b) Copy the nameidata provided as an argument and substitute the dentry
argument into it the copy.
(c) Call do_add_mount() to install the new vfsmount into the namespace's
mountpoint tree, thus making it accessible to userspace. Use the
nameidata set up in (b) as the destination.
If the mountpoint will be automatically expired, then do_add_mount()
should also be given the location of an expiration list (see further
down).
(d) Release the path in the nameidata argument and substitute in the new
vfsmount and its root dentry. The ref counts on these will need
incrementing.
See section "Mount Traps" of Documentation/filesystems/autofs4.txt
Then from userspace, you can just do something like:
@ -61,17 +35,18 @@ AUTOMATIC MOUNTPOINT EXPIRY
===========================
Automatic expiration of mountpoints is easy, provided you've mounted the
mountpoint to be expired in the automounting procedure outlined above.
mountpoint to be expired in the automounting procedure outlined separately.
To do expiration, you need to follow these steps:
(3) Create at least one list off which the vfsmounts to be expired can be
hung. Access to this list will be governed by the vfsmount_lock.
(1) Create at least one list off which the vfsmounts to be expired can be
hung.
(4) In step (2c) above, the call to do_add_mount() should be provided with a
pointer to this list. It will hang the vfsmount off of it if it succeeds.
(2) When a new mountpoint is created in the ->d_automount method, add
the mnt to the list using mnt_set_expiry()
mnt_set_expiry(newmnt, &afs_vfsmounts);
(5) When you want mountpoints to be expired, call mark_mounts_for_expiry()
(3) When you want mountpoints to be expired, call mark_mounts_for_expiry()
with a pointer to this list. This will process the list, marking every
vfsmount thereon for potential expiry on the next call.

View File

@ -483,3 +483,20 @@ in your dentry operations instead.
--
[mandatory]
->aio_read/->aio_write are gone. Use ->read_iter/->write_iter.
---
[recommended]
for embedded ("fast") symlinks just set inode->i_link to wherever the
symlink body is and use simple_follow_link() as ->follow_link().
--
[mandatory]
calling conventions for ->follow_link() have changed. Instead of returning
cookie and using nd_set_link() to store the body to traverse, we return
the body to traverse and store the cookie using explicit void ** argument.
nameidata isn't passed at all - nd_jump_link() doesn't need it and
nd_[gs]et_link() is gone.
--
[mandatory]
calling conventions for ->put_link() have changed. It gets inode instead of
dentry, it does not get nameidata at all and it gets called only when cookie
is non-NULL. Note that link body isn't available anymore, so if you need it,
store it as cookie.

View File

@ -350,8 +350,8 @@ struct inode_operations {
int (*rename2) (struct inode *, struct dentry *,
struct inode *, struct dentry *, unsigned int);
int (*readlink) (struct dentry *, char __user *,int);
void * (*follow_link) (struct dentry *, struct nameidata *);
void (*put_link) (struct dentry *, struct nameidata *, void *);
const char *(*follow_link) (struct dentry *, void **);
void (*put_link) (struct inode *, void *);
int (*permission) (struct inode *, int);
int (*get_acl)(struct inode *, int);
int (*setattr) (struct dentry *, struct iattr *);
@ -436,16 +436,18 @@ otherwise noted.
follow_link: called by the VFS to follow a symbolic link to the
inode it points to. Only required if you want to support
symbolic links. This method returns a void pointer cookie
that is passed to put_link().
symbolic links. This method returns the symlink body
to traverse (and possibly resets the current position with
nd_jump_link()). If the body won't go away until the inode
is gone, nothing else is needed; if it needs to be otherwise
pinned, the data needed to release whatever we'd grabbed
is to be stored in void * variable passed by address to
follow_link() instance.
put_link: called by the VFS to release resources allocated by
follow_link(). The cookie returned by follow_link() is passed
to this method as the last parameter. It is used by
filesystems such as NFS where page cache is not stable
(i.e. page that was installed when the symbolic link walk
started might not be in the page cache at the end of the
walk).
follow_link(). The cookie stored by follow_link() is passed
to this method as the last parameter; only called when
cookie isn't NULL.
permission: called by the VFS to check for access rights on a POSIX-like
filesystem.

View File

@ -189,22 +189,7 @@ static inline int ll_quota_off(struct super_block *sb, int off, int remount)
#endif
/*
* After 3.1, kernel's nameidata.intent.open.flags is different
* with lustre's lookup_intent.it_flags, as lustre's it_flags'
* lower bits equal to FMODE_xxx while kernel doesn't transliterate
* lower bits of nameidata.intent.open.flags to FMODE_xxx.
* */
#include <linux/version.h>
static inline int ll_namei_to_lookup_intent_flag(int flag)
{
#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 1, 0)
flag = (flag & ~O_ACCMODE) | OPEN_FMODE(flag);
#endif
return flag;
}
#include <linux/fs.h>
# define ll_umode_t umode_t

View File

@ -57,12 +57,6 @@
#define VM_FAULT_RETRY 0
#endif
/* Kernel 3.1 kills LOOKUP_CONTINUE, LOOKUP_PARENT is equivalent to it.
* seem kernel commit 49084c3bb2055c401f3493c13edae14d49128ca0 */
#ifndef LOOKUP_CONTINUE
#define LOOKUP_CONTINUE LOOKUP_PARENT
#endif
/** Only used on client-side for indicating the tail of dir hash/offset. */
#define LL_DIR_END_OFF 0x7fffffffffffffffULL
#define LL_DIR_END_OFF_32BIT 0x7fffffffUL

View File

@ -118,7 +118,7 @@ failed:
return rc;
}
static void *ll_follow_link(struct dentry *dentry, struct nameidata *nd)
static const char *ll_follow_link(struct dentry *dentry, void **cookie)
{
struct inode *inode = d_inode(dentry);
struct ptlrpc_request *request = NULL;
@ -126,32 +126,22 @@ static void *ll_follow_link(struct dentry *dentry, struct nameidata *nd)
char *symname = NULL;
CDEBUG(D_VFSTRACE, "VFS Op\n");
/* Limit the recursive symlink depth to 5 instead of default
* 8 links when kernel has 4k stack to prevent stack overflow.
* For 8k stacks we need to limit it to 7 for local servers. */
if (THREAD_SIZE < 8192 && current->link_count >= 6) {
rc = -ELOOP;
} else if (THREAD_SIZE == 8192 && current->link_count >= 8) {
rc = -ELOOP;
} else {
ll_inode_size_lock(inode);
rc = ll_readlink_internal(inode, &request, &symname);
ll_inode_size_unlock(inode);
}
ll_inode_size_lock(inode);
rc = ll_readlink_internal(inode, &request, &symname);
ll_inode_size_unlock(inode);
if (rc) {
ptlrpc_req_finished(request);
request = NULL;
symname = ERR_PTR(rc);
return ERR_PTR(rc);
}
nd_set_link(nd, symname);
/* symname may contain a pointer to the request message buffer,
* we delay request releasing until ll_put_link then.
*/
return request;
*cookie = request;
return symname;
}
static void ll_put_link(struct dentry *dentry, struct nameidata *nd, void *cookie)
static void ll_put_link(struct inode *unused, void *cookie)
{
ptlrpc_req_finished(cookie);
}

View File

@ -149,8 +149,6 @@ extern int v9fs_vfs_unlink(struct inode *i, struct dentry *d);
extern int v9fs_vfs_rmdir(struct inode *i, struct dentry *d);
extern int v9fs_vfs_rename(struct inode *old_dir, struct dentry *old_dentry,
struct inode *new_dir, struct dentry *new_dentry);
extern void v9fs_vfs_put_link(struct dentry *dentry, struct nameidata *nd,
void *p);
extern struct inode *v9fs_inode_from_fid(struct v9fs_session_info *v9ses,
struct p9_fid *fid,
struct super_block *sb, int new);

View File

@ -1223,101 +1223,44 @@ ino_t v9fs_qid2ino(struct p9_qid *qid)
return i;
}
/**
* v9fs_readlink - read a symlink's location (internal version)
* @dentry: dentry for symlink
* @buffer: buffer to load symlink location into
* @buflen: length of buffer
*
*/
static int v9fs_readlink(struct dentry *dentry, char *buffer, int buflen)
{
int retval;
struct v9fs_session_info *v9ses;
struct p9_fid *fid;
struct p9_wstat *st;
p9_debug(P9_DEBUG_VFS, " %pd\n", dentry);
retval = -EPERM;
v9ses = v9fs_dentry2v9ses(dentry);
fid = v9fs_fid_lookup(dentry);
if (IS_ERR(fid))
return PTR_ERR(fid);
if (!v9fs_proto_dotu(v9ses))
return -EBADF;
st = p9_client_stat(fid);
if (IS_ERR(st))
return PTR_ERR(st);
if (!(st->mode & P9_DMSYMLINK)) {
retval = -EINVAL;
goto done;
}
/* copy extension buffer into buffer */
retval = min(strlen(st->extension)+1, (size_t)buflen);
memcpy(buffer, st->extension, retval);
p9_debug(P9_DEBUG_VFS, "%pd -> %s (%.*s)\n",
dentry, st->extension, buflen, buffer);
done:
p9stat_free(st);
kfree(st);
return retval;
}
/**
* v9fs_vfs_follow_link - follow a symlink path
* @dentry: dentry for symlink
* @nd: nameidata
*
* @cookie: place to pass the data to put_link()
*/
static void *v9fs_vfs_follow_link(struct dentry *dentry, struct nameidata *nd)
static const char *v9fs_vfs_follow_link(struct dentry *dentry, void **cookie)
{
int len = 0;
char *link = __getname();
struct v9fs_session_info *v9ses = v9fs_dentry2v9ses(dentry);
struct p9_fid *fid = v9fs_fid_lookup(dentry);
struct p9_wstat *st;
char *res;
p9_debug(P9_DEBUG_VFS, "%pd\n", dentry);
if (!link)
link = ERR_PTR(-ENOMEM);
else {
len = v9fs_readlink(dentry, link, PATH_MAX);
if (IS_ERR(fid))
return ERR_CAST(fid);
if (len < 0) {
__putname(link);
link = ERR_PTR(len);
} else
link[min(len, PATH_MAX-1)] = 0;
if (!v9fs_proto_dotu(v9ses))
return ERR_PTR(-EBADF);
st = p9_client_stat(fid);
if (IS_ERR(st))
return ERR_CAST(st);
if (!(st->mode & P9_DMSYMLINK)) {
p9stat_free(st);
kfree(st);
return ERR_PTR(-EINVAL);
}
nd_set_link(nd, link);
res = st->extension;
st->extension = NULL;
if (strlen(res) >= PATH_MAX)
res[PATH_MAX - 1] = '\0';
return NULL;
}
/**
* v9fs_vfs_put_link - release a symlink path
* @dentry: dentry for symlink
* @nd: nameidata
* @p: unused
*
*/
void
v9fs_vfs_put_link(struct dentry *dentry, struct nameidata *nd, void *p)
{
char *s = nd_get_link(nd);
p9_debug(P9_DEBUG_VFS, " %pd %s\n",
dentry, IS_ERR(s) ? "<error>" : s);
if (!IS_ERR(s))
__putname(s);
p9stat_free(st);
kfree(st);
return *cookie = res;
}
/**
@ -1370,6 +1313,8 @@ v9fs_vfs_symlink(struct inode *dir, struct dentry *dentry, const char *symname)
return v9fs_vfs_mkspecial(dir, dentry, P9_DMSYMLINK, symname);
}
#define U32_MAX_DIGITS 10
/**
* v9fs_vfs_link - create a hardlink
* @old_dentry: dentry for file to link to
@ -1383,7 +1328,7 @@ v9fs_vfs_link(struct dentry *old_dentry, struct inode *dir,
struct dentry *dentry)
{
int retval;
char *name;
char name[1 + U32_MAX_DIGITS + 2]; /* sign + number + \n + \0 */
struct p9_fid *oldfid;
p9_debug(P9_DEBUG_VFS, " %lu,%pd,%pd\n",
@ -1393,20 +1338,12 @@ v9fs_vfs_link(struct dentry *old_dentry, struct inode *dir,
if (IS_ERR(oldfid))
return PTR_ERR(oldfid);
name = __getname();
if (unlikely(!name)) {
retval = -ENOMEM;
goto clunk_fid;
}
sprintf(name, "%d\n", oldfid->fid);
retval = v9fs_vfs_mkspecial(dir, dentry, P9_DMLINK, name);
__putname(name);
if (!retval) {
v9fs_refresh_inode(oldfid, d_inode(old_dentry));
v9fs_invalidate_inode_attr(dir);
}
clunk_fid:
p9_client_clunk(oldfid);
return retval;
}
@ -1425,7 +1362,7 @@ v9fs_vfs_mknod(struct inode *dir, struct dentry *dentry, umode_t mode, dev_t rde
{
struct v9fs_session_info *v9ses = v9fs_inode2v9ses(dir);
int retval;
char *name;
char name[2 + U32_MAX_DIGITS + 1 + U32_MAX_DIGITS + 1];
u32 perm;
p9_debug(P9_DEBUG_VFS, " %lu,%pd mode: %hx MAJOR: %u MINOR: %u\n",
@ -1435,26 +1372,16 @@ v9fs_vfs_mknod(struct inode *dir, struct dentry *dentry, umode_t mode, dev_t rde
if (!new_valid_dev(rdev))
return -EINVAL;
name = __getname();
if (!name)
return -ENOMEM;
/* build extension */
if (S_ISBLK(mode))
sprintf(name, "b %u %u", MAJOR(rdev), MINOR(rdev));
else if (S_ISCHR(mode))
sprintf(name, "c %u %u", MAJOR(rdev), MINOR(rdev));
else if (S_ISFIFO(mode))
else
*name = 0;
else if (S_ISSOCK(mode))
*name = 0;
else {
__putname(name);
return -EINVAL;
}
perm = unixmode2p9mode(v9ses, mode);
retval = v9fs_vfs_mkspecial(dir, dentry, perm, name);
__putname(name);
return retval;
}
@ -1530,7 +1457,7 @@ static const struct inode_operations v9fs_file_inode_operations = {
static const struct inode_operations v9fs_symlink_inode_operations = {
.readlink = generic_readlink,
.follow_link = v9fs_vfs_follow_link,
.put_link = v9fs_vfs_put_link,
.put_link = kfree_put_link,
.getattr = v9fs_vfs_getattr,
.setattr = v9fs_vfs_setattr,
};

View File

@ -905,41 +905,24 @@ error:
/**
* v9fs_vfs_follow_link_dotl - follow a symlink path
* @dentry: dentry for symlink
* @nd: nameidata
*
* @cookie: place to pass the data to put_link()
*/
static void *
v9fs_vfs_follow_link_dotl(struct dentry *dentry, struct nameidata *nd)
static const char *
v9fs_vfs_follow_link_dotl(struct dentry *dentry, void **cookie)
{
int retval;
struct p9_fid *fid;
char *link = __getname();
struct p9_fid *fid = v9fs_fid_lookup(dentry);
char *target;
int retval;
p9_debug(P9_DEBUG_VFS, "%pd\n", dentry);
if (!link) {
link = ERR_PTR(-ENOMEM);
goto ndset;
}
fid = v9fs_fid_lookup(dentry);
if (IS_ERR(fid)) {
__putname(link);
link = ERR_CAST(fid);
goto ndset;
}
if (IS_ERR(fid))
return ERR_CAST(fid);
retval = p9_client_readlink(fid, &target);
if (!retval) {
strcpy(link, target);
kfree(target);
goto ndset;
}
__putname(link);
link = ERR_PTR(retval);
ndset:
nd_set_link(nd, link);
return NULL;
if (retval)
return ERR_PTR(retval);
return *cookie = target;
}
int v9fs_refresh_inode_dotl(struct p9_fid *fid, struct inode *inode)
@ -1006,7 +989,7 @@ const struct inode_operations v9fs_file_inode_operations_dotl = {
const struct inode_operations v9fs_symlink_inode_operations_dotl = {
.readlink = generic_readlink,
.follow_link = v9fs_vfs_follow_link_dotl,
.put_link = v9fs_vfs_put_link,
.put_link = kfree_put_link,
.getattr = v9fs_vfs_getattr_dotl,
.setattr = v9fs_vfs_setattr_dotl,
.setxattr = generic_setxattr,

View File

@ -12,14 +12,13 @@
#include "autofs_i.h"
static void *autofs4_follow_link(struct dentry *dentry, struct nameidata *nd)
static const char *autofs4_follow_link(struct dentry *dentry, void **cookie)
{
struct autofs_sb_info *sbi = autofs4_sbi(dentry->d_sb);
struct autofs_info *ino = autofs4_dentry_ino(dentry);
if (ino && !autofs4_oz_mode(sbi))
ino->last_used = jiffies;
nd_set_link(nd, d_inode(dentry)->i_private);
return NULL;
return d_inode(dentry)->i_private;
}
const struct inode_operations autofs4_symlink_inode_operations = {

View File

@ -42,8 +42,7 @@ static struct inode *befs_iget(struct super_block *, unsigned long);
static struct inode *befs_alloc_inode(struct super_block *sb);
static void befs_destroy_inode(struct inode *inode);
static void befs_destroy_inodecache(void);
static void *befs_follow_link(struct dentry *, struct nameidata *);
static void *befs_fast_follow_link(struct dentry *, struct nameidata *);
static const char *befs_follow_link(struct dentry *, void **);
static int befs_utf2nls(struct super_block *sb, const char *in, int in_len,
char **out, int *out_len);
static int befs_nls2utf(struct super_block *sb, const char *in, int in_len,
@ -80,11 +79,6 @@ static const struct address_space_operations befs_aops = {
.bmap = befs_bmap,
};
static const struct inode_operations befs_fast_symlink_inode_operations = {
.readlink = generic_readlink,
.follow_link = befs_fast_follow_link,
};
static const struct inode_operations befs_symlink_inode_operations = {
.readlink = generic_readlink,
.follow_link = befs_follow_link,
@ -403,10 +397,12 @@ static struct inode *befs_iget(struct super_block *sb, unsigned long ino)
inode->i_op = &befs_dir_inode_operations;
inode->i_fop = &befs_dir_operations;
} else if (S_ISLNK(inode->i_mode)) {
if (befs_ino->i_flags & BEFS_LONG_SYMLINK)
if (befs_ino->i_flags & BEFS_LONG_SYMLINK) {
inode->i_op = &befs_symlink_inode_operations;
else
inode->i_op = &befs_fast_symlink_inode_operations;
} else {
inode->i_link = befs_ino->i_data.symlink;
inode->i_op = &simple_symlink_inode_operations;
}
} else {
befs_error(sb, "Inode %lu is not a regular file, "
"directory or symlink. THAT IS WRONG! BeFS has no "
@ -467,8 +463,8 @@ befs_destroy_inodecache(void)
* The data stream become link name. Unless the LONG_SYMLINK
* flag is set.
*/
static void *
befs_follow_link(struct dentry *dentry, struct nameidata *nd)
static const char *
befs_follow_link(struct dentry *dentry, void **cookie)
{
struct super_block *sb = dentry->d_sb;
struct befs_inode_info *befs_ino = BEFS_I(d_inode(dentry));
@ -478,33 +474,20 @@ befs_follow_link(struct dentry *dentry, struct nameidata *nd)
if (len == 0) {
befs_error(sb, "Long symlink with illegal length");
link = ERR_PTR(-EIO);
} else {
befs_debug(sb, "Follow long symlink");
link = kmalloc(len, GFP_NOFS);
if (!link) {
link = ERR_PTR(-ENOMEM);
} else if (befs_read_lsymlink(sb, data, link, len) != len) {
kfree(link);
befs_error(sb, "Failed to read entire long symlink");
link = ERR_PTR(-EIO);
} else {
link[len - 1] = '\0';
}
return ERR_PTR(-EIO);
}
nd_set_link(nd, link);
return NULL;
}
befs_debug(sb, "Follow long symlink");
static void *
befs_fast_follow_link(struct dentry *dentry, struct nameidata *nd)
{
struct befs_inode_info *befs_ino = BEFS_I(d_inode(dentry));
nd_set_link(nd, befs_ino->i_data.symlink);
return NULL;
link = kmalloc(len, GFP_NOFS);
if (!link)
return ERR_PTR(-ENOMEM);
if (befs_read_lsymlink(sb, data, link, len) != len) {
kfree(link);
befs_error(sb, "Failed to read entire long symlink");
return ERR_PTR(-EIO);
}
link[len - 1] = '\0';
return *cookie = link;
}
/*

View File

@ -6,7 +6,6 @@
#include <linux/string.h>
#include <linux/uaccess.h>
#include <linux/kernel.h>
#include <linux/namei.h>
#include <linux/writeback.h>
#include <linux/vmalloc.h>
#include <linux/posix_acl.h>
@ -819,6 +818,7 @@ static int fill_inode(struct inode *inode, struct page *locked_page,
else
kfree(sym); /* lost a race */
}
inode->i_link = ci->i_symlink;
break;
case S_IFDIR:
inode->i_op = &ceph_dir_iops;
@ -1691,16 +1691,9 @@ retry:
/*
* symlinks
*/
static void *ceph_sym_follow_link(struct dentry *dentry, struct nameidata *nd)
{
struct ceph_inode_info *ci = ceph_inode(d_inode(dentry));
nd_set_link(nd, ci->i_symlink);
return NULL;
}
static const struct inode_operations ceph_symlink_iops = {
.readlink = generic_readlink,
.follow_link = ceph_sym_follow_link,
.follow_link = simple_follow_link,
.setattr = ceph_setattr,
.getattr = ceph_getattr,
.setxattr = ceph_setxattr,

View File

@ -120,7 +120,7 @@ extern struct vfsmount *cifs_dfs_d_automount(struct path *path);
#endif
/* Functions related to symlinks */
extern void *cifs_follow_link(struct dentry *direntry, struct nameidata *nd);
extern const char *cifs_follow_link(struct dentry *direntry, void **cookie);
extern int cifs_readlink(struct dentry *direntry, char __user *buffer,
int buflen);
extern int cifs_symlink(struct inode *inode, struct dentry *direntry,

View File

@ -626,8 +626,8 @@ cifs_hl_exit:
return rc;
}
void *
cifs_follow_link(struct dentry *direntry, struct nameidata *nd)
const char *
cifs_follow_link(struct dentry *direntry, void **cookie)
{
struct inode *inode = d_inode(direntry);
int rc = -ENOMEM;
@ -643,16 +643,18 @@ cifs_follow_link(struct dentry *direntry, struct nameidata *nd)
tlink = cifs_sb_tlink(cifs_sb);
if (IS_ERR(tlink)) {
rc = PTR_ERR(tlink);
tlink = NULL;
goto out;
free_xid(xid);
return ERR_CAST(tlink);
}
tcon = tlink_tcon(tlink);
server = tcon->ses->server;
full_path = build_path_from_dentry(direntry);
if (!full_path)
goto out;
if (!full_path) {
free_xid(xid);
cifs_put_tlink(tlink);
return ERR_PTR(-ENOMEM);
}
cifs_dbg(FYI, "Full path: %s inode = 0x%p\n", full_path, inode);
@ -670,17 +672,13 @@ cifs_follow_link(struct dentry *direntry, struct nameidata *nd)
&target_path, cifs_sb);
kfree(full_path);
out:
free_xid(xid);
cifs_put_tlink(tlink);
if (rc != 0) {
kfree(target_path);
target_path = ERR_PTR(rc);
return ERR_PTR(rc);
}
free_xid(xid);
if (tlink)
cifs_put_tlink(tlink);
nd_set_link(nd, target_path);
return NULL;
return *cookie = target_path;
}
int

View File

@ -279,36 +279,27 @@ static int configfs_getlink(struct dentry *dentry, char * path)
}
static void *configfs_follow_link(struct dentry *dentry, struct nameidata *nd)
static const char *configfs_follow_link(struct dentry *dentry, void **cookie)
{
int error = -ENOMEM;
unsigned long page = get_zeroed_page(GFP_KERNEL);
int error;
if (page) {
error = configfs_getlink(dentry, (char *)page);
if (!error) {
nd_set_link(nd, (char *)page);
return (void *)page;
}
if (!page)
return ERR_PTR(-ENOMEM);
error = configfs_getlink(dentry, (char *)page);
if (!error) {
return *cookie = (void *)page;
}
nd_set_link(nd, ERR_PTR(error));
return NULL;
}
static void configfs_put_link(struct dentry *dentry, struct nameidata *nd,
void *cookie)
{
if (cookie) {
unsigned long page = (unsigned long)cookie;
free_page(page);
}
free_page(page);
return ERR_PTR(error);
}
const struct inode_operations configfs_symlink_inode_operations = {
.follow_link = configfs_follow_link,
.readlink = generic_readlink,
.put_link = configfs_put_link,
.put_link = free_page_put_link,
.setattr = configfs_setattr,
};

View File

@ -17,7 +17,6 @@
#include <linux/fs.h>
#include <linux/seq_file.h>
#include <linux/pagemap.h>
#include <linux/namei.h>
#include <linux/debugfs.h>
#include <linux/io.h>
#include <linux/slab.h>
@ -43,17 +42,6 @@ const struct file_operations debugfs_file_operations = {
.llseek = noop_llseek,
};
static void *debugfs_follow_link(struct dentry *dentry, struct nameidata *nd)
{
nd_set_link(nd, d_inode(dentry)->i_private);
return NULL;
}
const struct inode_operations debugfs_link_operations = {
.readlink = generic_readlink,
.follow_link = debugfs_follow_link,
};
static int debugfs_u8_set(void *data, u64 val)
{
*(u8 *)data = val;

View File

@ -174,7 +174,7 @@ static void debugfs_evict_inode(struct inode *inode)
truncate_inode_pages_final(&inode->i_data);
clear_inode(inode);
if (S_ISLNK(inode->i_mode))
kfree(inode->i_private);
kfree(inode->i_link);
}
static const struct super_operations debugfs_super_operations = {
@ -511,8 +511,8 @@ struct dentry *debugfs_create_symlink(const char *name, struct dentry *parent,
return failed_creating(dentry);
}
inode->i_mode = S_IFLNK | S_IRWXUGO;
inode->i_op = &debugfs_link_operations;
inode->i_private = link;
inode->i_op = &simple_symlink_inode_operations;
inode->i_link = link;
d_instantiate(dentry, inode);
return end_creating(dentry);
}

View File

@ -170,7 +170,6 @@ out_unlock:
* @directory_inode: inode of the new file's dentry's parent in ecryptfs
* @ecryptfs_dentry: New file's dentry in ecryptfs
* @mode: The mode of the new file
* @nd: nameidata of ecryptfs' parent's dentry & vfsmount
*
* Creates the underlying file and the eCryptfs inode which will link to
* it. It will also update the eCryptfs directory inode to mimic the
@ -384,7 +383,7 @@ static int ecryptfs_lookup_interpose(struct dentry *dentry,
* ecryptfs_lookup
* @ecryptfs_dir_inode: The eCryptfs directory inode
* @ecryptfs_dentry: The eCryptfs dentry that we are looking up
* @ecryptfs_nd: nameidata; may be NULL
* @flags: lookup flags
*
* Find a file on disk. If the file does not exist, then we'll add it to the
* dentry cache and continue on to read it from the disk.
@ -675,18 +674,16 @@ out:
return rc ? ERR_PTR(rc) : buf;
}
static void *ecryptfs_follow_link(struct dentry *dentry, struct nameidata *nd)
static const char *ecryptfs_follow_link(struct dentry *dentry, void **cookie)
{
size_t len;
char *buf = ecryptfs_readlink_lower(dentry, &len);
if (IS_ERR(buf))
goto out;
return buf;
fsstack_copy_attr_atime(d_inode(dentry),
d_inode(ecryptfs_dentry_to_lower(dentry)));
buf[len] = '\0';
out:
nd_set_link(nd, buf);
return NULL;
return *cookie = buf;
}
/**

View File

@ -16,5 +16,5 @@
libore-y := ore.o ore_raid.o
obj-$(CONFIG_ORE) += libore.o
exofs-y := inode.o file.o symlink.o namei.o dir.o super.o sys.o
exofs-y := inode.o file.o namei.o dir.o super.o sys.o
obj-$(CONFIG_EXOFS_FS) += exofs.o

View File

@ -207,10 +207,6 @@ extern const struct address_space_operations exofs_aops;
extern const struct inode_operations exofs_dir_inode_operations;
extern const struct inode_operations exofs_special_inode_operations;
/* symlink.c */
extern const struct inode_operations exofs_symlink_inode_operations;
extern const struct inode_operations exofs_fast_symlink_inode_operations;
/* exofs_init_comps will initialize an ore_components device array
* pointing to a single ore_comp struct, and a round-robin view
* of the device table.

View File

@ -1222,10 +1222,11 @@ struct inode *exofs_iget(struct super_block *sb, unsigned long ino)
inode->i_fop = &exofs_dir_operations;
inode->i_mapping->a_ops = &exofs_aops;
} else if (S_ISLNK(inode->i_mode)) {
if (exofs_inode_is_fast_symlink(inode))
inode->i_op = &exofs_fast_symlink_inode_operations;
else {
inode->i_op = &exofs_symlink_inode_operations;
if (exofs_inode_is_fast_symlink(inode)) {
inode->i_op = &simple_symlink_inode_operations;
inode->i_link = (char *)oi->i_data;
} else {
inode->i_op = &page_symlink_inode_operations;
inode->i_mapping->a_ops = &exofs_aops;
}
} else {

View File

@ -113,7 +113,7 @@ static int exofs_symlink(struct inode *dir, struct dentry *dentry,
oi = exofs_i(inode);
if (l > sizeof(oi->i_data)) {
/* slow symlink */
inode->i_op = &exofs_symlink_inode_operations;
inode->i_op = &page_symlink_inode_operations;
inode->i_mapping->a_ops = &exofs_aops;
memset(oi->i_data, 0, sizeof(oi->i_data));
@ -122,7 +122,8 @@ static int exofs_symlink(struct inode *dir, struct dentry *dentry,
goto out_fail;
} else {
/* fast symlink */
inode->i_op = &exofs_fast_symlink_inode_operations;
inode->i_op = &simple_symlink_inode_operations;
inode->i_link = (char *)oi->i_data;
memcpy(oi->i_data, symname, l);
inode->i_size = l-1;
}

View File

@ -1,55 +0,0 @@
/*
* Copyright (C) 2005, 2006
* Avishay Traeger (avishay@gmail.com)
* Copyright (C) 2008, 2009
* Boaz Harrosh <ooo@electrozaur.com>
*
* Copyrights for code taken from ext2:
* Copyright (C) 1992, 1993, 1994, 1995
* Remy Card (card@masi.ibp.fr)
* Laboratoire MASI - Institut Blaise Pascal
* Universite Pierre et Marie Curie (Paris VI)
* from
* linux/fs/minix/inode.c
* Copyright (C) 1991, 1992 Linus Torvalds
*
* This file is part of exofs.
*
* exofs is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation. Since it is based on ext2, and the only
* valid version of GPL for the Linux kernel is version 2, the only valid
* version of GPL for exofs is version 2.
*
* exofs is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with exofs; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <linux/namei.h>
#include "exofs.h"
static void *exofs_follow_link(struct dentry *dentry, struct nameidata *nd)
{
struct exofs_i_info *oi = exofs_i(d_inode(dentry));
nd_set_link(nd, (char *)oi->i_data);
return NULL;
}
const struct inode_operations exofs_symlink_inode_operations = {
.readlink = generic_readlink,
.follow_link = page_follow_link_light,
.put_link = page_put_link,
};
const struct inode_operations exofs_fast_symlink_inode_operations = {
.readlink = generic_readlink,
.follow_link = exofs_follow_link,
};

View File

@ -1403,6 +1403,7 @@ struct inode *ext2_iget (struct super_block *sb, unsigned long ino)
inode->i_mapping->a_ops = &ext2_aops;
} else if (S_ISLNK(inode->i_mode)) {
if (ext2_inode_is_fast_symlink(inode)) {
inode->i_link = (char *)ei->i_data;
inode->i_op = &ext2_fast_symlink_inode_operations;
nd_terminate_link(ei->i_data, inode->i_size,
sizeof(ei->i_data) - 1);

View File

@ -189,7 +189,8 @@ static int ext2_symlink (struct inode * dir, struct dentry * dentry,
} else {
/* fast symlink */
inode->i_op = &ext2_fast_symlink_inode_operations;
memcpy((char*)(EXT2_I(inode)->i_data),symname,l);
inode->i_link = (char*)EXT2_I(inode)->i_data;
memcpy(inode->i_link, symname, l);
inode->i_size = l-1;
}
mark_inode_dirty(inode);

View File

@ -19,14 +19,6 @@
#include "ext2.h"
#include "xattr.h"
#include <linux/namei.h>
static void *ext2_follow_link(struct dentry *dentry, struct nameidata *nd)
{
struct ext2_inode_info *ei = EXT2_I(d_inode(dentry));
nd_set_link(nd, (char *)ei->i_data);
return NULL;
}
const struct inode_operations ext2_symlink_inode_operations = {
.readlink = generic_readlink,
@ -43,7 +35,7 @@ const struct inode_operations ext2_symlink_inode_operations = {
const struct inode_operations ext2_fast_symlink_inode_operations = {
.readlink = generic_readlink,
.follow_link = ext2_follow_link,
.follow_link = simple_follow_link,
.setattr = ext2_setattr,
#ifdef CONFIG_EXT2_FS_XATTR
.setxattr = generic_setxattr,

View File

@ -2999,6 +2999,7 @@ struct inode *ext3_iget(struct super_block *sb, unsigned long ino)
inode->i_op = &ext3_fast_symlink_inode_operations;
nd_terminate_link(ei->i_data, inode->i_size,
sizeof(ei->i_data) - 1);
inode->i_link = (char *)ei->i_data;
} else {
inode->i_op = &ext3_symlink_inode_operations;
ext3_set_aops(inode);

View File

@ -2308,7 +2308,8 @@ retry:
}
} else {
inode->i_op = &ext3_fast_symlink_inode_operations;
memcpy((char*)&EXT3_I(inode)->i_data,symname,l);
inode->i_link = (char*)&EXT3_I(inode)->i_data;
memcpy(inode->i_link, symname, l);
inode->i_size = l-1;
}
EXT3_I(inode)->i_disksize = inode->i_size;

View File

@ -17,17 +17,9 @@
* ext3 symlink handling code
*/
#include <linux/namei.h>
#include "ext3.h"
#include "xattr.h"
static void * ext3_follow_link(struct dentry *dentry, struct nameidata *nd)
{
struct ext3_inode_info *ei = EXT3_I(d_inode(dentry));
nd_set_link(nd, (char*)ei->i_data);
return NULL;
}
const struct inode_operations ext3_symlink_inode_operations = {
.readlink = generic_readlink,
.follow_link = page_follow_link_light,
@ -43,7 +35,7 @@ const struct inode_operations ext3_symlink_inode_operations = {
const struct inode_operations ext3_fast_symlink_inode_operations = {
.readlink = generic_readlink,
.follow_link = ext3_follow_link,
.follow_link = simple_follow_link,
.setattr = ext3_setattr,
#ifdef CONFIG_EXT3_FS_XATTR
.setxattr = generic_setxattr,

View File

@ -2847,6 +2847,7 @@ extern int ext4_mpage_readpages(struct address_space *mapping,
unsigned nr_pages);
/* symlink.c */
extern const struct inode_operations ext4_encrypted_symlink_inode_operations;
extern const struct inode_operations ext4_symlink_inode_operations;
extern const struct inode_operations ext4_fast_symlink_inode_operations;

View File

@ -4213,8 +4213,11 @@ struct inode *ext4_iget(struct super_block *sb, unsigned long ino)
inode->i_op = &ext4_dir_inode_operations;
inode->i_fop = &ext4_dir_operations;
} else if (S_ISLNK(inode->i_mode)) {
if (ext4_inode_is_fast_symlink(inode) &&
!ext4_encrypted_inode(inode)) {
if (ext4_encrypted_inode(inode)) {
inode->i_op = &ext4_encrypted_symlink_inode_operations;
ext4_set_aops(inode);
} else if (ext4_inode_is_fast_symlink(inode)) {
inode->i_link = (char *)ei->i_data;
inode->i_op = &ext4_fast_symlink_inode_operations;
nd_terminate_link(ei->i_data, inode->i_size,
sizeof(ei->i_data) - 1);

View File

@ -3206,10 +3206,12 @@ static int ext4_symlink(struct inode *dir,
goto err_drop_inode;
sd->len = cpu_to_le16(ostr.len);
disk_link.name = (char *) sd;
inode->i_op = &ext4_encrypted_symlink_inode_operations;
}
if ((disk_link.len > EXT4_N_BLOCKS * 4)) {
inode->i_op = &ext4_symlink_inode_operations;
if (!encryption_required)
inode->i_op = &ext4_symlink_inode_operations;
ext4_set_aops(inode);
/*
* We cannot call page_symlink() with transaction started
@ -3249,9 +3251,10 @@ static int ext4_symlink(struct inode *dir,
} else {
/* clear the extent format for fast symlink */
ext4_clear_inode_flag(inode, EXT4_INODE_EXTENTS);
inode->i_op = encryption_required ?
&ext4_symlink_inode_operations :
&ext4_fast_symlink_inode_operations;
if (!encryption_required) {
inode->i_op = &ext4_fast_symlink_inode_operations;
inode->i_link = (char *)&EXT4_I(inode)->i_data;
}
memcpy((char *)&EXT4_I(inode)->i_data, disk_link.name,
disk_link.len);
inode->i_size = disk_link.len - 1;

View File

@ -23,7 +23,7 @@
#include "xattr.h"
#ifdef CONFIG_EXT4_FS_ENCRYPTION
static void *ext4_follow_link(struct dentry *dentry, struct nameidata *nd)
static const char *ext4_follow_link(struct dentry *dentry, void **cookie)
{
struct page *cpage = NULL;
char *caddr, *paddr = NULL;
@ -35,12 +35,9 @@ static void *ext4_follow_link(struct dentry *dentry, struct nameidata *nd)
int res;
u32 plen, max_size = inode->i_sb->s_blocksize;
if (!ext4_encrypted_inode(inode))
return page_follow_link_light(dentry, nd);
ctx = ext4_get_fname_crypto_ctx(inode, inode->i_sb->s_blocksize);
if (IS_ERR(ctx))
return ctx;
return ERR_CAST(ctx);
if (ext4_inode_is_fast_symlink(inode)) {
caddr = (char *) EXT4_I(inode)->i_data;
@ -49,7 +46,7 @@ static void *ext4_follow_link(struct dentry *dentry, struct nameidata *nd)
cpage = read_mapping_page(inode->i_mapping, 0, NULL);
if (IS_ERR(cpage)) {
ext4_put_fname_crypto_ctx(&ctx);
return cpage;
return ERR_CAST(cpage);
}
caddr = kmap(cpage);
caddr[size] = 0;
@ -80,13 +77,12 @@ static void *ext4_follow_link(struct dentry *dentry, struct nameidata *nd)
/* Null-terminate the name */
if (res <= plen)
paddr[res] = '\0';
nd_set_link(nd, paddr);
ext4_put_fname_crypto_ctx(&ctx);
if (cpage) {
kunmap(cpage);
page_cache_release(cpage);
}
return NULL;
return *cookie = paddr;
errout:
ext4_put_fname_crypto_ctx(&ctx);
if (cpage) {
@ -97,36 +93,22 @@ errout:
return ERR_PTR(res);
}
static void ext4_put_link(struct dentry *dentry, struct nameidata *nd,
void *cookie)
{
struct page *page = cookie;
if (!page) {
kfree(nd_get_link(nd));
} else {
kunmap(page);
page_cache_release(page);
}
}
const struct inode_operations ext4_encrypted_symlink_inode_operations = {
.readlink = generic_readlink,
.follow_link = ext4_follow_link,
.put_link = kfree_put_link,
.setattr = ext4_setattr,
.setxattr = generic_setxattr,
.getxattr = generic_getxattr,
.listxattr = ext4_listxattr,
.removexattr = generic_removexattr,
};
#endif
static void *ext4_follow_fast_link(struct dentry *dentry, struct nameidata *nd)
{
struct ext4_inode_info *ei = EXT4_I(d_inode(dentry));
nd_set_link(nd, (char *) ei->i_data);
return NULL;
}
const struct inode_operations ext4_symlink_inode_operations = {
.readlink = generic_readlink,
#ifdef CONFIG_EXT4_FS_ENCRYPTION
.follow_link = ext4_follow_link,
.put_link = ext4_put_link,
#else
.follow_link = page_follow_link_light,
.put_link = page_put_link,
#endif
.setattr = ext4_setattr,
.setxattr = generic_setxattr,
.getxattr = generic_getxattr,
@ -136,7 +118,7 @@ const struct inode_operations ext4_symlink_inode_operations = {
const struct inode_operations ext4_fast_symlink_inode_operations = {
.readlink = generic_readlink,
.follow_link = ext4_follow_fast_link,
.follow_link = simple_follow_link,
.setattr = ext4_setattr,
.setxattr = generic_setxattr,
.getxattr = generic_getxattr,

View File

@ -296,19 +296,15 @@ fail:
return err;
}
static void *f2fs_follow_link(struct dentry *dentry, struct nameidata *nd)
static const char *f2fs_follow_link(struct dentry *dentry, void **cookie)
{
struct page *page = page_follow_link_light(dentry, nd);
if (IS_ERR_OR_NULL(page))
return page;
/* this is broken symlink case */
if (*nd_get_link(nd) == 0) {
page_put_link(dentry, nd, page);
return ERR_PTR(-ENOENT);
const char *link = page_follow_link_light(dentry, cookie);
if (!IS_ERR(link) && !*link) {
/* this is broken symlink case */
page_put_link(NULL, *cookie);
link = ERR_PTR(-ENOENT);
}
return page;
return link;
}
static int f2fs_symlink(struct inode *dir, struct dentry *dentry,

View File

@ -50,9 +50,6 @@ extern daddr_t vxfs_bmap1(struct inode *, long);
/* vxfs_fshead.c */
extern int vxfs_read_fshead(struct super_block *);
/* vxfs_immed.c */
extern const struct inode_operations vxfs_immed_symlink_iops;
/* vxfs_inode.c */
extern const struct address_space_operations vxfs_immed_aops;
extern struct kmem_cache *vxfs_inode_cachep;

View File

@ -32,28 +32,14 @@
*/
#include <linux/fs.h>
#include <linux/pagemap.h>
#include <linux/namei.h>
#include "vxfs.h"
#include "vxfs_extern.h"
#include "vxfs_inode.h"
static void * vxfs_immed_follow_link(struct dentry *, struct nameidata *);
static int vxfs_immed_readpage(struct file *, struct page *);
/*
* Inode operations for immed symlinks.
*
* Unliked all other operations we do not go through the pagecache,
* but do all work directly on the inode.
*/
const struct inode_operations vxfs_immed_symlink_iops = {
.readlink = generic_readlink,
.follow_link = vxfs_immed_follow_link,
};
/*
* Address space operations for immed files and directories.
*/
@ -61,26 +47,6 @@ const struct address_space_operations vxfs_immed_aops = {
.readpage = vxfs_immed_readpage,
};
/**
* vxfs_immed_follow_link - follow immed symlink
* @dp: dentry for the link
* @np: pathname lookup data for the current path walk
*
* Description:
* vxfs_immed_follow_link restarts the pathname lookup with
* the data obtained from @dp.
*
* Returns:
* Zero on success, else a negative error code.
*/
static void *
vxfs_immed_follow_link(struct dentry *dp, struct nameidata *np)
{
struct vxfs_inode_info *vip = VXFS_INO(d_inode(dp));
nd_set_link(np, vip->vii_immed.vi_immed);
return NULL;
}
/**
* vxfs_immed_readpage - read part of an immed inode into pagecache
* @file: file context (unused)

View File

@ -35,6 +35,7 @@
#include <linux/pagemap.h>
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/namei.h>
#include "vxfs.h"
#include "vxfs_inode.h"
@ -327,8 +328,10 @@ vxfs_iget(struct super_block *sbp, ino_t ino)
ip->i_op = &page_symlink_inode_operations;
ip->i_mapping->a_ops = &vxfs_aops;
} else {
ip->i_op = &vxfs_immed_symlink_iops;
vip->vii_immed.vi_immed[ip->i_size] = '\0';
ip->i_op = &simple_symlink_inode_operations;
ip->i_link = vip->vii_immed.vi_immed;
nd_terminate_link(ip->i_link, ip->i_size,
sizeof(vip->vii_immed.vi_immed) - 1);
}
} else
init_special_inode(ip, ip->i_mode, old_decode_dev(vip->vii_rdev));

View File

@ -1365,7 +1365,7 @@ static int fuse_readdir(struct file *file, struct dir_context *ctx)
return err;
}
static char *read_link(struct dentry *dentry)
static const char *fuse_follow_link(struct dentry *dentry, void **cookie)
{
struct inode *inode = d_inode(dentry);
struct fuse_conn *fc = get_fuse_conn(inode);
@ -1389,28 +1389,12 @@ static char *read_link(struct dentry *dentry)
link = ERR_PTR(ret);
} else {
link[ret] = '\0';
*cookie = link;
}
fuse_invalidate_atime(inode);
return link;
}
static void free_link(char *link)
{
if (!IS_ERR(link))
free_page((unsigned long) link);
}
static void *fuse_follow_link(struct dentry *dentry, struct nameidata *nd)
{
nd_set_link(nd, read_link(dentry));
return NULL;
}
static void fuse_put_link(struct dentry *dentry, struct nameidata *nd, void *c)
{
free_link(nd_get_link(nd));
}
static int fuse_dir_open(struct inode *inode, struct file *file)
{
return fuse_open_common(inode, file, true);
@ -1926,7 +1910,7 @@ static const struct inode_operations fuse_common_inode_operations = {
static const struct inode_operations fuse_symlink_inode_operations = {
.setattr = fuse_setattr,
.follow_link = fuse_follow_link,
.put_link = fuse_put_link,
.put_link = free_page_put_link,
.readlink = generic_readlink,
.getattr = fuse_getattr,
.setxattr = fuse_setxattr,

View File

@ -1548,7 +1548,7 @@ out:
* Returns: 0 on success or error code
*/
static void *gfs2_follow_link(struct dentry *dentry, struct nameidata *nd)
static const char *gfs2_follow_link(struct dentry *dentry, void **cookie)
{
struct gfs2_inode *ip = GFS2_I(d_inode(dentry));
struct gfs2_holder i_gh;
@ -1561,8 +1561,7 @@ static void *gfs2_follow_link(struct dentry *dentry, struct nameidata *nd)
error = gfs2_glock_nq(&i_gh);
if (error) {
gfs2_holder_uninit(&i_gh);
nd_set_link(nd, ERR_PTR(error));
return NULL;
return ERR_PTR(error);
}
size = (unsigned int)i_size_read(&ip->i_inode);
@ -1586,8 +1585,9 @@ static void *gfs2_follow_link(struct dentry *dentry, struct nameidata *nd)
brelse(dibh);
out:
gfs2_glock_dq_uninit(&i_gh);
nd_set_link(nd, buf);
return NULL;
if (!IS_ERR(buf))
*cookie = buf;
return buf;
}
/**

View File

@ -892,7 +892,7 @@ static const struct inode_operations hostfs_dir_iops = {
.setattr = hostfs_setattr,
};
static void *hostfs_follow_link(struct dentry *dentry, struct nameidata *nd)
static const char *hostfs_follow_link(struct dentry *dentry, void **cookie)
{
char *link = __getname();
if (link) {
@ -906,21 +906,18 @@ static void *hostfs_follow_link(struct dentry *dentry, struct nameidata *nd)
}
if (err < 0) {
__putname(link);
link = ERR_PTR(err);
return ERR_PTR(err);
}
} else {
link = ERR_PTR(-ENOMEM);
return ERR_PTR(-ENOMEM);
}
nd_set_link(nd, link);
return NULL;
return *cookie = link;
}
static void hostfs_put_link(struct dentry *dentry, struct nameidata *nd, void *cookie)
static void hostfs_put_link(struct inode *unused, void *cookie)
{
char *s = nd_get_link(nd);
if (!IS_ERR(s))
__putname(s);
__putname(cookie);
}
static const struct inode_operations hostfs_link_iops = {

View File

@ -642,20 +642,19 @@ static int hppfs_readlink(struct dentry *dentry, char __user *buffer,
buflen);
}
static void *hppfs_follow_link(struct dentry *dentry, struct nameidata *nd)
static const char *hppfs_follow_link(struct dentry *dentry, void **cookie)
{
struct dentry *proc_dentry = HPPFS_I(d_inode(dentry))->proc_dentry;
return d_inode(proc_dentry)->i_op->follow_link(proc_dentry, nd);
return d_inode(proc_dentry)->i_op->follow_link(proc_dentry, cookie);
}
static void hppfs_put_link(struct dentry *dentry, struct nameidata *nd,
void *cookie)
static void hppfs_put_link(struct inode *inode, void *cookie)
{
struct dentry *proc_dentry = HPPFS_I(d_inode(dentry))->proc_dentry;
struct inode *proc_inode = d_inode(HPPFS_I(inode)->proc_dentry);
if (d_inode(proc_dentry)->i_op->put_link)
d_inode(proc_dentry)->i_op->put_link(proc_dentry, nd, cookie);
if (proc_inode->i_op->put_link)
proc_inode->i_op->put_link(proc_inode, cookie);
}
static const struct inode_operations hppfs_dir_iops = {

View File

@ -152,6 +152,7 @@ int inode_init_always(struct super_block *sb, struct inode *inode)
inode->i_pipe = NULL;
inode->i_bdev = NULL;
inode->i_cdev = NULL;
inode->i_link = NULL;
inode->i_rdev = 0;
inode->dirtied_when = 0;
@ -1584,36 +1585,47 @@ static int update_time(struct inode *inode, struct timespec *time, int flags)
* This function automatically handles read only file systems and media,
* as well as the "noatime" flag and inode specific "noatime" markers.
*/
bool atime_needs_update(const struct path *path, struct inode *inode)
{
struct vfsmount *mnt = path->mnt;
struct timespec now;
if (inode->i_flags & S_NOATIME)
return false;
if (IS_NOATIME(inode))
return false;
if ((inode->i_sb->s_flags & MS_NODIRATIME) && S_ISDIR(inode->i_mode))
return false;
if (mnt->mnt_flags & MNT_NOATIME)
return false;
if ((mnt->mnt_flags & MNT_NODIRATIME) && S_ISDIR(inode->i_mode))
return false;
now = current_fs_time(inode->i_sb);
if (!relatime_need_update(mnt, inode, now))
return false;
if (timespec_equal(&inode->i_atime, &now))
return false;
return true;
}
void touch_atime(const struct path *path)
{
struct vfsmount *mnt = path->mnt;
struct inode *inode = d_inode(path->dentry);
struct timespec now;
if (inode->i_flags & S_NOATIME)
return;
if (IS_NOATIME(inode))
return;
if ((inode->i_sb->s_flags & MS_NODIRATIME) && S_ISDIR(inode->i_mode))
return;
if (mnt->mnt_flags & MNT_NOATIME)
return;
if ((mnt->mnt_flags & MNT_NODIRATIME) && S_ISDIR(inode->i_mode))
return;
now = current_fs_time(inode->i_sb);
if (!relatime_need_update(mnt, inode, now))
return;
if (timespec_equal(&inode->i_atime, &now))
if (!atime_needs_update(path, inode))
return;
if (!sb_start_write_trylock(inode->i_sb))
return;
if (__mnt_want_write(mnt))
if (__mnt_want_write(mnt) != 0)
goto skip_update;
/*
* File systems can error out when updating inodes if they need to
@ -1624,6 +1636,7 @@ void touch_atime(const struct path *path)
* We may also fail on filesystems that have the ability to make parts
* of the fs read only, e.g. subvolumes in Btrfs.
*/
now = current_fs_time(inode->i_sb);
update_time(inode, &now, S_ATIME);
__mnt_drop_write(mnt);
skip_update:

View File

@ -354,6 +354,7 @@ static int jffs2_symlink (struct inode *dir_i, struct dentry *dentry, const char
ret = -ENOMEM;
goto fail;
}
inode->i_link = f->target;
jffs2_dbg(1, "%s(): symlink's target '%s' cached\n",
__func__, (char *)f->target);

View File

@ -294,6 +294,7 @@ struct inode *jffs2_iget(struct super_block *sb, unsigned long ino)
case S_IFLNK:
inode->i_op = &jffs2_symlink_inode_operations;
inode->i_link = f->target;
break;
case S_IFDIR:

View File

@ -9,58 +9,15 @@
*
*/
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/namei.h>
#include "nodelist.h"
static void *jffs2_follow_link(struct dentry *dentry, struct nameidata *nd);
const struct inode_operations jffs2_symlink_inode_operations =
{
.readlink = generic_readlink,
.follow_link = jffs2_follow_link,
.follow_link = simple_follow_link,
.setattr = jffs2_setattr,
.setxattr = jffs2_setxattr,
.getxattr = jffs2_getxattr,
.listxattr = jffs2_listxattr,
.removexattr = jffs2_removexattr
};
static void *jffs2_follow_link(struct dentry *dentry, struct nameidata *nd)
{
struct jffs2_inode_info *f = JFFS2_INODE_INFO(d_inode(dentry));
char *p = (char *)f->target;
/*
* We don't acquire the f->sem mutex here since the only data we
* use is f->target.
*
* 1. If we are here the inode has already built and f->target has
* to point to the target path.
* 2. Nobody uses f->target (if the inode is symlink's inode). The
* exception is inode freeing function which frees f->target. But
* it can't be called while we are here and before VFS has
* stopped using our f->target string which we provide by means of
* nd_set_link() call.
*/
if (!p) {
pr_err("%s(): can't find symlink target\n", __func__);
p = ERR_PTR(-EIO);
}
jffs2_dbg(1, "%s(): target path is '%s'\n",
__func__, (char *)f->target);
nd_set_link(nd, p);
/*
* We will unlock the f->sem mutex but VFS will use the f->target string. This is safe
* since the only way that may cause f->target to be changed is iput() operation.
* But VFS will not use f->target after iput() has been called.
*/
return NULL;
}

View File

@ -63,11 +63,12 @@ struct inode *jfs_iget(struct super_block *sb, unsigned long ino)
inode->i_mapping->a_ops = &jfs_aops;
} else {
inode->i_op = &jfs_fast_symlink_inode_operations;
inode->i_link = JFS_IP(inode)->i_inline;
/*
* The inline data should be null-terminated, but
* don't let on-disk corruption crash the kernel
*/
JFS_IP(inode)->i_inline[inode->i_size] = '\0';
inode->i_link[inode->i_size] = '\0';
}
} else {
inode->i_op = &jfs_file_inode_operations;

View File

@ -880,7 +880,6 @@ static int jfs_symlink(struct inode *dip, struct dentry *dentry,
int ssize; /* source pathname size */
struct btstack btstack;
struct inode *ip = d_inode(dentry);
unchar *i_fastsymlink;
s64 xlen = 0;
int bmask = 0, xsize;
s64 xaddr;
@ -946,8 +945,8 @@ static int jfs_symlink(struct inode *dip, struct dentry *dentry,
if (ssize <= IDATASIZE) {
ip->i_op = &jfs_fast_symlink_inode_operations;
i_fastsymlink = JFS_IP(ip)->i_inline;
memcpy(i_fastsymlink, name, ssize);
ip->i_link = JFS_IP(ip)->i_inline;
memcpy(ip->i_link, name, ssize);
ip->i_size = ssize - 1;
/*

View File

@ -17,21 +17,13 @@
*/
#include <linux/fs.h>
#include <linux/namei.h>
#include "jfs_incore.h"
#include "jfs_inode.h"
#include "jfs_xattr.h"
static void *jfs_follow_link(struct dentry *dentry, struct nameidata *nd)
{
char *s = JFS_IP(d_inode(dentry))->i_inline;
nd_set_link(nd, s);
return NULL;
}
const struct inode_operations jfs_fast_symlink_inode_operations = {
.readlink = generic_readlink,
.follow_link = jfs_follow_link,
.follow_link = simple_follow_link,
.setattr = jfs_setattr,
.setxattr = jfs_setxattr,
.getxattr = jfs_getxattr,

View File

@ -112,25 +112,18 @@ static int kernfs_getlink(struct dentry *dentry, char *path)
return error;
}
static void *kernfs_iop_follow_link(struct dentry *dentry, struct nameidata *nd)
static const char *kernfs_iop_follow_link(struct dentry *dentry, void **cookie)
{
int error = -ENOMEM;
unsigned long page = get_zeroed_page(GFP_KERNEL);
if (page) {
error = kernfs_getlink(dentry, (char *) page);
if (error < 0)
free_page((unsigned long)page);
}
nd_set_link(nd, error ? ERR_PTR(error) : (char *)page);
return NULL;
}
static void kernfs_iop_put_link(struct dentry *dentry, struct nameidata *nd,
void *cookie)
{
char *page = nd_get_link(nd);
if (!IS_ERR(page))
if (!page)
return ERR_PTR(-ENOMEM);
error = kernfs_getlink(dentry, (char *)page);
if (unlikely(error < 0)) {
free_page((unsigned long)page);
return ERR_PTR(error);
}
return *cookie = (char *)page;
}
const struct inode_operations kernfs_symlink_iops = {
@ -140,7 +133,7 @@ const struct inode_operations kernfs_symlink_iops = {
.listxattr = kernfs_iop_listxattr,
.readlink = generic_readlink,
.follow_link = kernfs_iop_follow_link,
.put_link = kernfs_iop_put_link,
.put_link = free_page_put_link,
.setattr = kernfs_iop_setattr,
.getattr = kernfs_iop_getattr,
.permission = kernfs_iop_permission,

View File

@ -1024,15 +1024,18 @@ int noop_fsync(struct file *file, loff_t start, loff_t end, int datasync)
}
EXPORT_SYMBOL(noop_fsync);
void kfree_put_link(struct dentry *dentry, struct nameidata *nd,
void *cookie)
void kfree_put_link(struct inode *unused, void *cookie)
{
char *s = nd_get_link(nd);
if (!IS_ERR(s))
kfree(s);
kfree(cookie);
}
EXPORT_SYMBOL(kfree_put_link);
void free_page_put_link(struct inode *unused, void *cookie)
{
free_page((unsigned long) cookie);
}
EXPORT_SYMBOL(free_page_put_link);
/*
* nop .set_page_dirty method so that people can use .page_mkwrite on
* anon inodes.
@ -1093,3 +1096,15 @@ simple_nosetlease(struct file *filp, long arg, struct file_lock **flp,
return -EINVAL;
}
EXPORT_SYMBOL(simple_nosetlease);
const char *simple_follow_link(struct dentry *dentry, void **cookie)
{
return d_inode(dentry)->i_link;
}
EXPORT_SYMBOL(simple_follow_link);
const struct inode_operations simple_symlink_inode_operations = {
.follow_link = simple_follow_link,
.readlink = generic_readlink
};
EXPORT_SYMBOL(simple_symlink_inode_operations);

View File

@ -779,6 +779,7 @@ fail:
const struct inode_operations logfs_symlink_iops = {
.readlink = generic_readlink,
.follow_link = page_follow_link_light,
.put_link = page_put_link,
};
const struct inode_operations logfs_dir_iops = {

View File

@ -88,6 +88,7 @@ static inline int is_mounted(struct vfsmount *mnt)
extern struct mount *__lookup_mnt(struct vfsmount *, struct dentry *);
extern struct mount *__lookup_mnt_last(struct vfsmount *, struct dentry *);
extern int __legitimize_mnt(struct vfsmount *, unsigned);
extern bool legitimize_mnt(struct vfsmount *, unsigned);
extern void __detach_mounts(struct dentry *dentry);

1455
fs/namei.c

File diff suppressed because it is too large Load Diff

View File

@ -590,24 +590,35 @@ static void delayed_free_vfsmnt(struct rcu_head *head)
}
/* call under rcu_read_lock */
bool legitimize_mnt(struct vfsmount *bastard, unsigned seq)
int __legitimize_mnt(struct vfsmount *bastard, unsigned seq)
{
struct mount *mnt;
if (read_seqretry(&mount_lock, seq))
return false;
return 1;
if (bastard == NULL)
return true;
return 0;
mnt = real_mount(bastard);
mnt_add_count(mnt, 1);
if (likely(!read_seqretry(&mount_lock, seq)))
return true;
return 0;
if (bastard->mnt_flags & MNT_SYNC_UMOUNT) {
mnt_add_count(mnt, -1);
return false;
return 1;
}
return -1;
}
/* call under rcu_read_lock */
bool legitimize_mnt(struct vfsmount *bastard, unsigned seq)
{
int res = __legitimize_mnt(bastard, seq);
if (likely(!res))
return true;
if (unlikely(res < 0)) {
rcu_read_unlock();
mntput(bastard);
rcu_read_lock();
}
rcu_read_unlock();
mntput(bastard);
rcu_read_lock();
return false;
}

View File

@ -20,7 +20,6 @@
#include <linux/stat.h>
#include <linux/mm.h>
#include <linux/string.h>
#include <linux/namei.h>
/* Symlink caching in the page cache is even more simplistic
* and straight-forward than readdir caching.
@ -43,7 +42,7 @@ error:
return -EIO;
}
static void *nfs_follow_link(struct dentry *dentry, struct nameidata *nd)
static const char *nfs_follow_link(struct dentry *dentry, void **cookie)
{
struct inode *inode = d_inode(dentry);
struct page *page;
@ -51,19 +50,13 @@ static void *nfs_follow_link(struct dentry *dentry, struct nameidata *nd)
err = ERR_PTR(nfs_revalidate_mapping(inode, inode->i_mapping));
if (err)
goto read_failed;
return err;
page = read_cache_page(&inode->i_data, 0,
(filler_t *)nfs_symlink_filler, inode);
if (IS_ERR(page)) {
err = page;
goto read_failed;
}
nd_set_link(nd, kmap(page));
return page;
read_failed:
nd_set_link(nd, err);
return NULL;
if (IS_ERR(page))
return ERR_CAST(page);
*cookie = page;
return kmap(page);
}
/*

View File

@ -35,7 +35,7 @@
* ntfs_lookup - find the inode represented by a dentry in a directory inode
* @dir_ino: directory inode in which to look for the inode
* @dent: dentry representing the inode to look for
* @nd: lookup nameidata
* @flags: lookup flags
*
* In short, ntfs_lookup() looks for the inode represented by the dentry @dent
* in the directory inode @dir_ino and if found attaches the inode to the

View File

@ -367,7 +367,7 @@ retry:
if (res)
goto out;
inode = path.dentry->d_inode;
inode = d_backing_inode(path.dentry);
if ((mode & MAY_EXEC) && S_ISREG(inode->i_mode)) {
/*

View File

@ -140,11 +140,12 @@ struct ovl_link_data {
void *cookie;
};
static void *ovl_follow_link(struct dentry *dentry, struct nameidata *nd)
static const char *ovl_follow_link(struct dentry *dentry, void **cookie)
{
void *ret;
struct dentry *realdentry;
struct inode *realinode;
struct ovl_link_data *data = NULL;
const char *ret;
realdentry = ovl_dentry_real(dentry);
realinode = realdentry->d_inode;
@ -152,28 +153,28 @@ static void *ovl_follow_link(struct dentry *dentry, struct nameidata *nd)
if (WARN_ON(!realinode->i_op->follow_link))
return ERR_PTR(-EPERM);
ret = realinode->i_op->follow_link(realdentry, nd);
if (IS_ERR(ret))
return ret;
if (realinode->i_op->put_link) {
struct ovl_link_data *data;
data = kmalloc(sizeof(struct ovl_link_data), GFP_KERNEL);
if (!data) {
realinode->i_op->put_link(realdentry, nd, ret);
if (!data)
return ERR_PTR(-ENOMEM);
}
data->realdentry = realdentry;
data->cookie = ret;
return data;
} else {
return NULL;
}
ret = realinode->i_op->follow_link(realdentry, cookie);
if (IS_ERR_OR_NULL(ret)) {
kfree(data);
return ret;
}
if (data)
data->cookie = *cookie;
*cookie = data;
return ret;
}
static void ovl_put_link(struct dentry *dentry, struct nameidata *nd, void *c)
static void ovl_put_link(struct inode *unused, void *c)
{
struct inode *realinode;
struct ovl_link_data *data = c;
@ -182,7 +183,7 @@ static void ovl_put_link(struct dentry *dentry, struct nameidata *nd, void *c)
return;
realinode = data->realdentry->d_inode;
realinode->i_op->put_link(data->realdentry, nd, data->cookie);
realinode->i_op->put_link(realinode, data->cookie);
kfree(data);
}

View File

@ -1380,7 +1380,7 @@ static int proc_exe_link(struct dentry *dentry, struct path *exe_path)
return -ENOENT;
}
static void *proc_pid_follow_link(struct dentry *dentry, struct nameidata *nd)
static const char *proc_pid_follow_link(struct dentry *dentry, void **cookie)
{
struct inode *inode = d_inode(dentry);
struct path path;
@ -1394,7 +1394,7 @@ static void *proc_pid_follow_link(struct dentry *dentry, struct nameidata *nd)
if (error)
goto out;
nd_jump_link(nd, &path);
nd_jump_link(&path);
return NULL;
out:
return ERR_PTR(error);

View File

@ -23,7 +23,6 @@
#include <linux/slab.h>
#include <linux/mount.h>
#include <linux/magic.h>
#include <linux/namei.h>
#include <asm/uaccess.h>
@ -394,16 +393,16 @@ static const struct file_operations proc_reg_file_ops_no_compat = {
};
#endif
static void *proc_follow_link(struct dentry *dentry, struct nameidata *nd)
static const char *proc_follow_link(struct dentry *dentry, void **cookie)
{
struct proc_dir_entry *pde = PDE(d_inode(dentry));
if (unlikely(!use_pde(pde)))
return ERR_PTR(-EINVAL);
nd_set_link(nd, pde->data);
return pde;
*cookie = pde;
return pde->data;
}
static void proc_put_link(struct dentry *dentry, struct nameidata *nd, void *p)
static void proc_put_link(struct inode *unused, void *p)
{
unuse_pde(p);
}

View File

@ -30,7 +30,7 @@ static const struct proc_ns_operations *ns_entries[] = {
&mntns_operations,
};
static void *proc_ns_follow_link(struct dentry *dentry, struct nameidata *nd)
static const char *proc_ns_follow_link(struct dentry *dentry, void **cookie)
{
struct inode *inode = d_inode(dentry);
const struct proc_ns_operations *ns_ops = PROC_I(inode)->ns_ops;
@ -45,7 +45,7 @@ static void *proc_ns_follow_link(struct dentry *dentry, struct nameidata *nd)
if (ptrace_may_access(task, PTRACE_MODE_READ)) {
error = ns_get_path(&ns_path, task, ns_ops);
if (!error)
nd_jump_link(nd, &ns_path);
nd_jump_link(&ns_path);
}
put_task_struct(task);
return error;

View File

@ -1,5 +1,4 @@
#include <linux/sched.h>
#include <linux/namei.h>
#include <linux/slab.h>
#include <linux/pid_namespace.h>
#include "internal.h"
@ -19,21 +18,20 @@ static int proc_self_readlink(struct dentry *dentry, char __user *buffer,
return readlink_copy(buffer, buflen, tmp);
}
static void *proc_self_follow_link(struct dentry *dentry, struct nameidata *nd)
static const char *proc_self_follow_link(struct dentry *dentry, void **cookie)
{
struct pid_namespace *ns = dentry->d_sb->s_fs_info;
pid_t tgid = task_tgid_nr_ns(current, ns);
char *name = ERR_PTR(-ENOENT);
if (tgid) {
/* 11 for max length of signed int in decimal + NULL term */
name = kmalloc(12, GFP_KERNEL);
if (!name)
name = ERR_PTR(-ENOMEM);
else
sprintf(name, "%d", tgid);
}
nd_set_link(nd, name);
return NULL;
char *name;
if (!tgid)
return ERR_PTR(-ENOENT);
/* 11 for max length of signed int in decimal + NULL term */
name = kmalloc(12, GFP_KERNEL);
if (!name)
return ERR_PTR(-ENOMEM);
sprintf(name, "%d", tgid);
return *cookie = name;
}
static const struct inode_operations proc_self_inode_operations = {

View File

@ -1,5 +1,4 @@
#include <linux/sched.h>
#include <linux/namei.h>
#include <linux/slab.h>
#include <linux/pid_namespace.h>
#include "internal.h"
@ -20,21 +19,20 @@ static int proc_thread_self_readlink(struct dentry *dentry, char __user *buffer,
return readlink_copy(buffer, buflen, tmp);
}
static void *proc_thread_self_follow_link(struct dentry *dentry, struct nameidata *nd)
static const char *proc_thread_self_follow_link(struct dentry *dentry, void **cookie)
{
struct pid_namespace *ns = dentry->d_sb->s_fs_info;
pid_t tgid = task_tgid_nr_ns(current, ns);
pid_t pid = task_pid_nr_ns(current, ns);
char *name = ERR_PTR(-ENOENT);
if (pid) {
name = kmalloc(PROC_NUMBUF + 6 + PROC_NUMBUF, GFP_KERNEL);
if (!name)
name = ERR_PTR(-ENOMEM);
else
sprintf(name, "%d/task/%d", tgid, pid);
}
nd_set_link(nd, name);
return NULL;
char *name;
if (!pid)
return ERR_PTR(-ENOENT);
name = kmalloc(PROC_NUMBUF + 6 + PROC_NUMBUF, GFP_KERNEL);
if (!name)
return ERR_PTR(-ENOMEM);
sprintf(name, "%d/task/%d", tgid, pid);
return *cookie = name;
}
static const struct inode_operations proc_thread_self_inode_operations = {

View File

@ -5,4 +5,4 @@
obj-$(CONFIG_SYSV_FS) += sysv.o
sysv-objs := ialloc.o balloc.o inode.o itree.o file.o dir.o \
namei.o super.o symlink.o
namei.o super.o

View File

@ -166,8 +166,9 @@ void sysv_set_inode(struct inode *inode, dev_t rdev)
inode->i_op = &sysv_symlink_inode_operations;
inode->i_mapping->a_ops = &sysv_aops;
} else {
inode->i_op = &sysv_fast_symlink_inode_operations;
nd_terminate_link(SYSV_I(inode)->i_data, inode->i_size,
inode->i_op = &simple_symlink_inode_operations;
inode->i_link = (char *)SYSV_I(inode)->i_data;
nd_terminate_link(inode->i_link, inode->i_size,
sizeof(SYSV_I(inode)->i_data) - 1);
}
} else

View File

@ -1,20 +0,0 @@
/*
* linux/fs/sysv/symlink.c
*
* Handling of System V filesystem fast symlinks extensions.
* Aug 2001, Christoph Hellwig (hch@infradead.org)
*/
#include "sysv.h"
#include <linux/namei.h>
static void *sysv_follow_link(struct dentry *dentry, struct nameidata *nd)
{
nd_set_link(nd, (char *)SYSV_I(d_inode(dentry))->i_data);
return NULL;
}
const struct inode_operations sysv_fast_symlink_inode_operations = {
.readlink = generic_readlink,
.follow_link = sysv_follow_link,
};

View File

@ -161,7 +161,6 @@ extern ino_t sysv_inode_by_name(struct dentry *);
extern const struct inode_operations sysv_file_inode_operations;
extern const struct inode_operations sysv_dir_inode_operations;
extern const struct inode_operations sysv_fast_symlink_inode_operations;
extern const struct file_operations sysv_file_operations;
extern const struct file_operations sysv_dir_operations;
extern const struct address_space_operations sysv_aops;

View File

@ -889,6 +889,7 @@ static int ubifs_symlink(struct inode *dir, struct dentry *dentry,
memcpy(ui->data, symname, len);
((char *)ui->data)[len] = '\0';
inode->i_link = ui->data;
/*
* The terminating zero byte is not written to the flash media and it
* is put just to make later in-memory string processing simpler. Thus,

View File

@ -51,7 +51,6 @@
#include "ubifs.h"
#include <linux/mount.h>
#include <linux/namei.h>
#include <linux/slab.h>
static int read_block(struct inode *inode, void *addr, unsigned int block,
@ -1300,14 +1299,6 @@ static void ubifs_invalidatepage(struct page *page, unsigned int offset,
ClearPageChecked(page);
}
static void *ubifs_follow_link(struct dentry *dentry, struct nameidata *nd)
{
struct ubifs_inode *ui = ubifs_inode(d_inode(dentry));
nd_set_link(nd, ui->data);
return NULL;
}
int ubifs_fsync(struct file *file, loff_t start, loff_t end, int datasync)
{
struct inode *inode = file->f_mapping->host;
@ -1570,7 +1561,7 @@ const struct inode_operations ubifs_file_inode_operations = {
const struct inode_operations ubifs_symlink_inode_operations = {
.readlink = generic_readlink,
.follow_link = ubifs_follow_link,
.follow_link = simple_follow_link,
.setattr = ubifs_setattr,
.getattr = ubifs_getattr,
.setxattr = ubifs_setxattr,

View File

@ -195,6 +195,7 @@ struct inode *ubifs_iget(struct super_block *sb, unsigned long inum)
}
memcpy(ui->data, ino->data, ui->data_len);
((char *)ui->data)[ui->data_len] = '\0';
inode->i_link = ui->data;
break;
case S_IFBLK:
case S_IFCHR:

View File

@ -572,9 +572,10 @@ static void ufs_set_inode_ops(struct inode *inode)
inode->i_fop = &ufs_dir_operations;
inode->i_mapping->a_ops = &ufs_aops;
} else if (S_ISLNK(inode->i_mode)) {
if (!inode->i_blocks)
if (!inode->i_blocks) {
inode->i_op = &ufs_fast_symlink_inode_operations;
else {
inode->i_link = (char *)UFS_I(inode)->i_u1.i_symlink;
} else {
inode->i_op = &ufs_symlink_inode_operations;
inode->i_mapping->a_ops = &ufs_aops;
}

View File

@ -144,7 +144,8 @@ static int ufs_symlink (struct inode * dir, struct dentry * dentry,
} else {
/* fast symlink */
inode->i_op = &ufs_fast_symlink_inode_operations;
memcpy(UFS_I(inode)->i_u1.i_symlink, symname, l);
inode->i_link = (char *)UFS_I(inode)->i_u1.i_symlink;
memcpy(inode->i_link, symname, l);
inode->i_size = l-1;
}
mark_inode_dirty(inode);

View File

@ -25,23 +25,12 @@
* ext2 symlink handling code
*/
#include <linux/fs.h>
#include <linux/namei.h>
#include "ufs_fs.h"
#include "ufs.h"
static void *ufs_follow_link(struct dentry *dentry, struct nameidata *nd)
{
struct ufs_inode_info *p = UFS_I(d_inode(dentry));
nd_set_link(nd, (char*)p->i_u1.i_symlink);
return NULL;
}
const struct inode_operations ufs_fast_symlink_inode_operations = {
.readlink = generic_readlink,
.follow_link = ufs_follow_link,
.follow_link = simple_follow_link,
.setattr = ufs_setattr,
};

View File

@ -41,7 +41,6 @@
#include <linux/capability.h>
#include <linux/xattr.h>
#include <linux/namei.h>
#include <linux/posix_acl.h>
#include <linux/security.h>
#include <linux/fiemap.h>
@ -414,10 +413,10 @@ xfs_vn_rename(
* we need to be very careful about how much stack we use.
* uio is kmalloced for this reason...
*/
STATIC void *
STATIC const char *
xfs_vn_follow_link(
struct dentry *dentry,
struct nameidata *nd)
void **cookie)
{
char *link;
int error = -ENOMEM;
@ -430,14 +429,12 @@ xfs_vn_follow_link(
if (unlikely(error))
goto out_kfree;
nd_set_link(nd, link);
return NULL;
return *cookie = link;
out_kfree:
kfree(link);
out_err:
nd_set_link(nd, ERR_PTR(error));
return NULL;
return ERR_PTR(error);
}
STATIC int

View File

@ -45,7 +45,6 @@ extern struct dentry *arch_debugfs_dir;
/* declared over in file.c */
extern const struct file_operations debugfs_file_operations;
extern const struct inode_operations debugfs_link_operations;
struct dentry *debugfs_create_file(const char *name, umode_t mode,
struct dentry *parent, void *data,

View File

@ -38,7 +38,6 @@ struct backing_dev_info;
struct export_operations;
struct hd_geometry;
struct iovec;
struct nameidata;
struct kiocb;
struct kobject;
struct pipe_inode_info;
@ -656,6 +655,7 @@ struct inode {
struct pipe_inode_info *i_pipe;
struct block_device *i_bdev;
struct cdev *i_cdev;
char *i_link;
};
__u32 i_generation;
@ -1607,12 +1607,12 @@ struct file_operations {
struct inode_operations {
struct dentry * (*lookup) (struct inode *,struct dentry *, unsigned int);
void * (*follow_link) (struct dentry *, struct nameidata *);
const char * (*follow_link) (struct dentry *, void **);
int (*permission) (struct inode *, int);
struct posix_acl * (*get_acl)(struct inode *, int);
int (*readlink) (struct dentry *, char __user *,int);
void (*put_link) (struct dentry *, struct nameidata *, void *);
void (*put_link) (struct inode *, void *);
int (*create) (struct inode *,struct dentry *, umode_t, bool);
int (*link) (struct dentry *,struct inode *,struct dentry *);
@ -1879,6 +1879,7 @@ enum file_time_flags {
S_VERSION = 8,
};
extern bool atime_needs_update(const struct path *, struct inode *);
extern void touch_atime(const struct path *);
static inline void file_accessed(struct file *file)
{
@ -2704,13 +2705,14 @@ extern const struct file_operations generic_ro_fops;
extern int readlink_copy(char __user *, int, const char *);
extern int page_readlink(struct dentry *, char __user *, int);
extern void *page_follow_link_light(struct dentry *, struct nameidata *);
extern void page_put_link(struct dentry *, struct nameidata *, void *);
extern const char *page_follow_link_light(struct dentry *, void **);
extern void page_put_link(struct inode *, void *);
extern int __page_symlink(struct inode *inode, const char *symname, int len,
int nofs);
extern int page_symlink(struct inode *inode, const char *symname, int len);
extern const struct inode_operations page_symlink_inode_operations;
extern void kfree_put_link(struct dentry *, struct nameidata *, void *);
extern void kfree_put_link(struct inode *, void *);
extern void free_page_put_link(struct inode *, void *);
extern int generic_readlink(struct dentry *, char __user *, int);
extern void generic_fillattr(struct inode *, struct kstat *);
int vfs_getattr_nosec(struct path *path, struct kstat *stat);
@ -2721,6 +2723,8 @@ void __inode_sub_bytes(struct inode *inode, loff_t bytes);
void inode_sub_bytes(struct inode *inode, loff_t bytes);
loff_t inode_get_bytes(struct inode *inode);
void inode_set_bytes(struct inode *inode, loff_t bytes);
const char *simple_follow_link(struct dentry *, void **);
extern const struct inode_operations simple_symlink_inode_operations;
extern int iterate_dir(struct file *, struct dir_context *);

View File

@ -1,16 +1,15 @@
#ifndef _LINUX_NAMEI_H
#define _LINUX_NAMEI_H
#include <linux/dcache.h>
#include <linux/errno.h>
#include <linux/linkage.h>
#include <linux/kernel.h>
#include <linux/path.h>
struct vfsmount;
struct nameidata;
#include <linux/fcntl.h>
#include <linux/errno.h>
enum { MAX_NESTED_LINKS = 8 };
#define MAXSYMLINKS 40
/*
* Type of the last component on LOOKUP_PARENT
*/
@ -45,13 +44,29 @@ enum {LAST_NORM, LAST_ROOT, LAST_DOT, LAST_DOTDOT, LAST_BIND};
#define LOOKUP_ROOT 0x2000
#define LOOKUP_EMPTY 0x4000
extern int user_path_at(int, const char __user *, unsigned, struct path *);
extern int user_path_at_empty(int, const char __user *, unsigned, struct path *, int *empty);
#define user_path(name, path) user_path_at(AT_FDCWD, name, LOOKUP_FOLLOW, path)
#define user_lpath(name, path) user_path_at(AT_FDCWD, name, 0, path)
#define user_path_dir(name, path) \
user_path_at(AT_FDCWD, name, LOOKUP_FOLLOW | LOOKUP_DIRECTORY, path)
static inline int user_path_at(int dfd, const char __user *name, unsigned flags,
struct path *path)
{
return user_path_at_empty(dfd, name, flags, path, NULL);
}
static inline int user_path(const char __user *name, struct path *path)
{
return user_path_at_empty(AT_FDCWD, name, LOOKUP_FOLLOW, path, NULL);
}
static inline int user_lpath(const char __user *name, struct path *path)
{
return user_path_at_empty(AT_FDCWD, name, 0, path, NULL);
}
static inline int user_path_dir(const char __user *name, struct path *path)
{
return user_path_at_empty(AT_FDCWD, name,
LOOKUP_FOLLOW | LOOKUP_DIRECTORY, path, NULL);
}
extern int kern_path(const char *, unsigned, struct path *);
@ -70,9 +85,7 @@ extern int follow_up(struct path *);
extern struct dentry *lock_rename(struct dentry *, struct dentry *);
extern void unlock_rename(struct dentry *, struct dentry *);
extern void nd_jump_link(struct nameidata *nd, struct path *path);
extern void nd_set_link(struct nameidata *nd, char *path);
extern char *nd_get_link(struct nameidata *nd);
extern void nd_jump_link(struct path *path);
static inline void nd_terminate_link(void *name, size_t len, size_t maxlen)
{

View File

@ -132,6 +132,7 @@ struct fs_struct;
struct perf_event_context;
struct blk_plug;
struct filename;
struct nameidata;
#define VMACACHE_BITS 2
#define VMACACHE_SIZE (1U << VMACACHE_BITS)
@ -1461,7 +1462,7 @@ struct task_struct {
it with task_lock())
- initialized normally by setup_new_exec */
/* file system info */
int link_count, total_link_count;
struct nameidata *nameidata;
#ifdef CONFIG_SYSVIPC
/* ipc stuff */
struct sysv_sem sysvsem;

View File

@ -43,7 +43,6 @@ struct file;
struct vfsmount;
struct path;
struct qstr;
struct nameidata;
struct iattr;
struct fown_struct;
struct file_operations;
@ -477,7 +476,8 @@ static inline void security_free_mnt_opts(struct security_mnt_opts *opts)
* @inode_follow_link:
* Check permission to follow a symbolic link when looking up a pathname.
* @dentry contains the dentry structure for the link.
* @nd contains the nameidata structure for the parent directory.
* @inode contains the inode, which itself is not stable in RCU-walk
* @rcu indicates whether we are in RCU-walk mode.
* Return 0 if permission is granted.
* @inode_permission:
* Check permission before accessing an inode. This hook is called by the
@ -1553,7 +1553,8 @@ struct security_operations {
int (*inode_rename) (struct inode *old_dir, struct dentry *old_dentry,
struct inode *new_dir, struct dentry *new_dentry);
int (*inode_readlink) (struct dentry *dentry);
int (*inode_follow_link) (struct dentry *dentry, struct nameidata *nd);
int (*inode_follow_link) (struct dentry *dentry, struct inode *inode,
bool rcu);
int (*inode_permission) (struct inode *inode, int mask);
int (*inode_setattr) (struct dentry *dentry, struct iattr *attr);
int (*inode_getattr) (const struct path *path);
@ -1839,7 +1840,8 @@ int security_inode_rename(struct inode *old_dir, struct dentry *old_dentry,
struct inode *new_dir, struct dentry *new_dentry,
unsigned int flags);
int security_inode_readlink(struct dentry *dentry);
int security_inode_follow_link(struct dentry *dentry, struct nameidata *nd);
int security_inode_follow_link(struct dentry *dentry, struct inode *inode,
bool rcu);
int security_inode_permission(struct inode *inode, int mask);
int security_inode_setattr(struct dentry *dentry, struct iattr *attr);
int security_inode_getattr(const struct path *path);
@ -2242,7 +2244,8 @@ static inline int security_inode_readlink(struct dentry *dentry)
}
static inline int security_inode_follow_link(struct dentry *dentry,
struct nameidata *nd)
struct inode *inode,
bool rcu)
{
return 0;
}

View File

@ -2451,6 +2451,7 @@ static int shmem_symlink(struct inode *dir, struct dentry *dentry, const char *s
return -ENOMEM;
}
inode->i_op = &shmem_short_symlink_operations;
inode->i_link = info->symlink;
} else {
error = shmem_getpage(inode, 0, &page, SGP_WRITE, NULL);
if (error) {
@ -2474,30 +2475,23 @@ static int shmem_symlink(struct inode *dir, struct dentry *dentry, const char *s
return 0;
}
static void *shmem_follow_short_symlink(struct dentry *dentry, struct nameidata *nd)
{
nd_set_link(nd, SHMEM_I(d_inode(dentry))->symlink);
return NULL;
}
static void *shmem_follow_link(struct dentry *dentry, struct nameidata *nd)
static const char *shmem_follow_link(struct dentry *dentry, void **cookie)
{
struct page *page = NULL;
int error = shmem_getpage(d_inode(dentry), 0, &page, SGP_READ, NULL);
nd_set_link(nd, error ? ERR_PTR(error) : kmap(page));
if (page)
unlock_page(page);
return page;
if (error)
return ERR_PTR(error);
unlock_page(page);
*cookie = page;
return kmap(page);
}
static void shmem_put_link(struct dentry *dentry, struct nameidata *nd, void *cookie)
static void shmem_put_link(struct inode *unused, void *cookie)
{
if (!IS_ERR(nd_get_link(nd))) {
struct page *page = cookie;
kunmap(page);
mark_page_accessed(page);
page_cache_release(page);
}
struct page *page = cookie;
kunmap(page);
mark_page_accessed(page);
page_cache_release(page);
}
#ifdef CONFIG_TMPFS_XATTR
@ -2642,7 +2636,7 @@ static ssize_t shmem_listxattr(struct dentry *dentry, char *buffer, size_t size)
static const struct inode_operations shmem_short_symlink_operations = {
.readlink = generic_readlink,
.follow_link = shmem_follow_short_symlink,
.follow_link = simple_follow_link,
#ifdef CONFIG_TMPFS_XATTR
.setxattr = shmem_setxattr,
.getxattr = shmem_getxattr,

View File

@ -209,8 +209,8 @@ static int cap_inode_readlink(struct dentry *dentry)
return 0;
}
static int cap_inode_follow_link(struct dentry *dentry,
struct nameidata *nameidata)
static int cap_inode_follow_link(struct dentry *dentry, struct inode *inode,
bool rcu)
{
return 0;
}

View File

@ -581,11 +581,12 @@ int security_inode_readlink(struct dentry *dentry)
return security_ops->inode_readlink(dentry);
}
int security_inode_follow_link(struct dentry *dentry, struct nameidata *nd)
int security_inode_follow_link(struct dentry *dentry, struct inode *inode,
bool rcu)
{
if (unlikely(IS_PRIVATE(d_backing_inode(dentry))))
if (unlikely(IS_PRIVATE(inode)))
return 0;
return security_ops->inode_follow_link(dentry, nd);
return security_ops->inode_follow_link(dentry, inode, rcu);
}
int security_inode_permission(struct inode *inode, int mask)

View File

@ -761,7 +761,23 @@ int avc_has_perm(u32 ssid, u32 tsid, u16 tclass,
rc = avc_has_perm_noaudit(ssid, tsid, tclass, requested, 0, &avd);
rc2 = avc_audit(ssid, tsid, tclass, requested, &avd, rc, auditdata);
rc2 = avc_audit(ssid, tsid, tclass, requested, &avd, rc, auditdata, 0);
if (rc2)
return rc2;
return rc;
}
int avc_has_perm_flags(u32 ssid, u32 tsid, u16 tclass,
u32 requested, struct common_audit_data *auditdata,
int flags)
{
struct av_decision avd;
int rc, rc2;
rc = avc_has_perm_noaudit(ssid, tsid, tclass, requested, 0, &avd);
rc2 = avc_audit(ssid, tsid, tclass, requested, &avd, rc,
auditdata, flags);
if (rc2)
return rc2;
return rc;

View File

@ -1564,7 +1564,7 @@ static int cred_has_capability(const struct cred *cred,
rc = avc_has_perm_noaudit(sid, sid, sclass, av, 0, &avd);
if (audit == SECURITY_CAP_AUDIT) {
int rc2 = avc_audit(sid, sid, sclass, av, &avd, rc, &ad);
int rc2 = avc_audit(sid, sid, sclass, av, &avd, rc, &ad, 0);
if (rc2)
return rc2;
}
@ -2861,11 +2861,23 @@ static int selinux_inode_readlink(struct dentry *dentry)
return dentry_has_perm(cred, dentry, FILE__READ);
}
static int selinux_inode_follow_link(struct dentry *dentry, struct nameidata *nameidata)
static int selinux_inode_follow_link(struct dentry *dentry, struct inode *inode,
bool rcu)
{
const struct cred *cred = current_cred();
struct common_audit_data ad;
struct inode_security_struct *isec;
u32 sid;
return dentry_has_perm(cred, dentry, FILE__READ);
validate_creds(cred);
ad.type = LSM_AUDIT_DATA_DENTRY;
ad.u.dentry = dentry;
sid = cred_sid(cred);
isec = inode->i_security;
return avc_has_perm_flags(sid, isec->sid, isec->sclass, FILE__READ, &ad,
rcu ? MAY_NOT_BLOCK : 0);
}
static noinline int audit_inode_permission(struct inode *inode,

View File

@ -130,7 +130,8 @@ static inline int avc_audit(u32 ssid, u32 tsid,
u16 tclass, u32 requested,
struct av_decision *avd,
int result,
struct common_audit_data *a)
struct common_audit_data *a,
int flags)
{
u32 audited, denied;
audited = avc_audit_required(requested, avd, result, 0, &denied);
@ -138,7 +139,7 @@ static inline int avc_audit(u32 ssid, u32 tsid,
return 0;
return slow_avc_audit(ssid, tsid, tclass,
requested, audited, denied, result,
a, 0);
a, flags);
}
#define AVC_STRICT 1 /* Ignore permissive mode. */
@ -150,6 +151,10 @@ int avc_has_perm_noaudit(u32 ssid, u32 tsid,
int avc_has_perm(u32 ssid, u32 tsid,
u16 tclass, u32 requested,
struct common_audit_data *auditdata);
int avc_has_perm_flags(u32 ssid, u32 tsid,
u16 tclass, u32 requested,
struct common_audit_data *auditdata,
int flags);
u32 avc_policy_seqno(void);