From 680baacbca69d18a6d7315374ad83d05ac9c0977 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Sat, 2 May 2015 13:32:22 -0400 Subject: new ->follow_link() and ->put_link() calling conventions a) instead of storing the symlink body (via nd_set_link()) and returning an opaque pointer later passed to ->put_link(), ->follow_link() _stores_ that opaque pointer (into void * passed by address by caller) and returns the symlink body. Returning ERR_PTR() on error, NULL on jump (procfs magic symlinks) and pointer to symlink body for normal symlinks. Stored pointer is ignored in all cases except the last one. Storing NULL for opaque pointer (or not storing it at all) means no call of ->put_link(). b) the body used to be passed to ->put_link() implicitly (via nameidata). Now only the opaque pointer is. In the cases when we used the symlink body to free stuff, ->follow_link() now should store it as opaque pointer in addition to returning it. Signed-off-by: Al Viro --- Documentation/filesystems/Locking | 4 ++-- Documentation/filesystems/vfs.txt | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) (limited to 'Documentation') diff --git a/Documentation/filesystems/Locking b/Documentation/filesystems/Locking index 0a926e2ba3ab..7fa6c4ac858c 100644 --- a/Documentation/filesystems/Locking +++ b/Documentation/filesystems/Locking @@ -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 **, struct nameidata *); + void (*put_link) (struct dentry *, void *); void (*truncate) (struct inode *); int (*permission) (struct inode *, int, unsigned int); int (*get_acl)(struct inode *, int); diff --git a/Documentation/filesystems/vfs.txt b/Documentation/filesystems/vfs.txt index 5d833b32bbcd..1c6b03ac2e5a 100644 --- a/Documentation/filesystems/vfs.txt +++ b/Documentation/filesystems/vfs.txt @@ -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 **, struct nameidata *); + void (*put_link) (struct dentry *, void *); int (*permission) (struct inode *, int); int (*get_acl)(struct inode *, int); int (*setattr) (struct dentry *, struct iattr *); -- cgit v1.2.3 From 6e77137b363b8d866ac29c5a0c95e953614fb2d8 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Sat, 2 May 2015 13:37:52 -0400 Subject: don't pass nameidata to ->follow_link() its only use is getting passed to nd_jump_link(), which can obtain it from current->nameidata Signed-off-by: Al Viro --- Documentation/filesystems/Locking | 2 +- Documentation/filesystems/vfs.txt | 2 +- drivers/staging/lustre/lustre/llite/symlink.c | 2 +- fs/9p/vfs_inode.c | 2 +- fs/9p/vfs_inode_dotl.c | 2 +- fs/autofs4/symlink.c | 2 +- fs/befs/linuxvfs.c | 4 ++-- fs/cifs/cifsfs.h | 2 +- fs/cifs/link.c | 2 +- fs/configfs/symlink.c | 2 +- fs/ecryptfs/inode.c | 2 +- fs/ext4/symlink.c | 2 +- fs/f2fs/namei.c | 4 ++-- fs/fuse/dir.c | 2 +- fs/gfs2/inode.c | 2 +- fs/hostfs/hostfs_kern.c | 2 +- fs/hppfs/hppfs.c | 4 ++-- fs/kernfs/symlink.c | 2 +- fs/libfs.c | 2 +- fs/namei.c | 11 ++++++----- fs/nfs/symlink.c | 2 +- fs/overlayfs/inode.c | 4 ++-- fs/proc/base.c | 4 ++-- fs/proc/inode.c | 2 +- fs/proc/namespaces.c | 4 ++-- fs/proc/self.c | 2 +- fs/proc/thread_self.c | 2 +- fs/xfs/xfs_iops.c | 3 +-- include/linux/fs.h | 6 +++--- include/linux/namei.h | 2 +- mm/shmem.c | 2 +- 31 files changed, 44 insertions(+), 44 deletions(-) (limited to 'Documentation') diff --git a/Documentation/filesystems/Locking b/Documentation/filesystems/Locking index 7fa6c4ac858c..5b5b4f54c033 100644 --- a/Documentation/filesystems/Locking +++ b/Documentation/filesystems/Locking @@ -50,7 +50,7 @@ prototypes: int (*rename2) (struct inode *, struct dentry *, struct inode *, struct dentry *, unsigned int); int (*readlink) (struct dentry *, char __user *,int); - const char *(*follow_link) (struct dentry *, void **, struct nameidata *); + const char *(*follow_link) (struct dentry *, void **); void (*put_link) (struct dentry *, void *); void (*truncate) (struct inode *); int (*permission) (struct inode *, int, unsigned int); diff --git a/Documentation/filesystems/vfs.txt b/Documentation/filesystems/vfs.txt index 1c6b03ac2e5a..0dec8c880be6 100644 --- a/Documentation/filesystems/vfs.txt +++ b/Documentation/filesystems/vfs.txt @@ -350,7 +350,7 @@ struct inode_operations { int (*rename2) (struct inode *, struct dentry *, struct inode *, struct dentry *, unsigned int); int (*readlink) (struct dentry *, char __user *,int); - const char *(*follow_link) (struct dentry *, void **, struct nameidata *); + const char *(*follow_link) (struct dentry *, void **); void (*put_link) (struct dentry *, void *); int (*permission) (struct inode *, int); int (*get_acl)(struct inode *, int); diff --git a/drivers/staging/lustre/lustre/llite/symlink.c b/drivers/staging/lustre/lustre/llite/symlink.c index da6d9d17c50d..f3be3bf0f66f 100644 --- a/drivers/staging/lustre/lustre/llite/symlink.c +++ b/drivers/staging/lustre/lustre/llite/symlink.c @@ -118,7 +118,7 @@ failed: return rc; } -static const char *ll_follow_link(struct dentry *dentry, void **cookie, 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; diff --git a/fs/9p/vfs_inode.c b/fs/9p/vfs_inode.c index 7cc70a39a1d8..271f51af2f75 100644 --- a/fs/9p/vfs_inode.c +++ b/fs/9p/vfs_inode.c @@ -1230,7 +1230,7 @@ ino_t v9fs_qid2ino(struct p9_qid *qid) * */ -static const char *v9fs_vfs_follow_link(struct dentry *dentry, void **cookie, struct nameidata *nd) +static const char *v9fs_vfs_follow_link(struct dentry *dentry, void **cookie) { struct v9fs_session_info *v9ses = v9fs_dentry2v9ses(dentry); struct p9_fid *fid = v9fs_fid_lookup(dentry); diff --git a/fs/9p/vfs_inode_dotl.c b/fs/9p/vfs_inode_dotl.c index ae062ffa0f1f..16658ed677c9 100644 --- a/fs/9p/vfs_inode_dotl.c +++ b/fs/9p/vfs_inode_dotl.c @@ -910,7 +910,7 @@ error: */ static const char * -v9fs_vfs_follow_link_dotl(struct dentry *dentry, void **cookie, struct nameidata *nd) +v9fs_vfs_follow_link_dotl(struct dentry *dentry, void **cookie) { struct p9_fid *fid = v9fs_fid_lookup(dentry); char *target; diff --git a/fs/autofs4/symlink.c b/fs/autofs4/symlink.c index 9c6a07739c9b..da0c33481bc0 100644 --- a/fs/autofs4/symlink.c +++ b/fs/autofs4/symlink.c @@ -12,7 +12,7 @@ #include "autofs_i.h" -static const char *autofs4_follow_link(struct dentry *dentry, void **cookie, 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); diff --git a/fs/befs/linuxvfs.c b/fs/befs/linuxvfs.c index 3a1aefb86a11..46aedacfa6a8 100644 --- a/fs/befs/linuxvfs.c +++ b/fs/befs/linuxvfs.c @@ -42,7 +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 const char *befs_follow_link(struct dentry *, void **, struct nameidata *nd); +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, @@ -464,7 +464,7 @@ befs_destroy_inodecache(void) * flag is set. */ static const char * -befs_follow_link(struct dentry *dentry, void **cookie, struct nameidata *nd) +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)); diff --git a/fs/cifs/cifsfs.h b/fs/cifs/cifsfs.h index 61012da7e9d8..a782b22904e4 100644 --- a/fs/cifs/cifsfs.h +++ b/fs/cifs/cifsfs.h @@ -120,7 +120,7 @@ extern struct vfsmount *cifs_dfs_d_automount(struct path *path); #endif /* Functions related to symlinks */ -extern const char *cifs_follow_link(struct dentry *direntry, void **cookie, 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, diff --git a/fs/cifs/link.c b/fs/cifs/link.c index 4a439c2c0c7f..546f86ab09aa 100644 --- a/fs/cifs/link.c +++ b/fs/cifs/link.c @@ -627,7 +627,7 @@ cifs_hl_exit: } const char * -cifs_follow_link(struct dentry *direntry, void **cookie, struct nameidata *nd) +cifs_follow_link(struct dentry *direntry, void **cookie) { struct inode *inode = d_inode(direntry); int rc = -ENOMEM; diff --git a/fs/configfs/symlink.c b/fs/configfs/symlink.c index fac8e8517f33..0ace75649009 100644 --- a/fs/configfs/symlink.c +++ b/fs/configfs/symlink.c @@ -279,7 +279,7 @@ static int configfs_getlink(struct dentry *dentry, char * path) } -static const char *configfs_follow_link(struct dentry *dentry, void **cookie, struct nameidata *nd) +static const char *configfs_follow_link(struct dentry *dentry, void **cookie) { unsigned long page = get_zeroed_page(GFP_KERNEL); int error; diff --git a/fs/ecryptfs/inode.c b/fs/ecryptfs/inode.c index cdb9d6c4532d..73d20ae92478 100644 --- a/fs/ecryptfs/inode.c +++ b/fs/ecryptfs/inode.c @@ -675,7 +675,7 @@ out: return rc ? ERR_PTR(rc) : buf; } -static const char *ecryptfs_follow_link(struct dentry *dentry, void **cookie, struct nameidata *nd) +static const char *ecryptfs_follow_link(struct dentry *dentry, void **cookie) { size_t len; char *buf = ecryptfs_readlink_lower(dentry, &len); diff --git a/fs/ext4/symlink.c b/fs/ext4/symlink.c index afec475aaf5c..ba5bd18a9825 100644 --- a/fs/ext4/symlink.c +++ b/fs/ext4/symlink.c @@ -23,7 +23,7 @@ #include "xattr.h" #ifdef CONFIG_EXT4_FS_ENCRYPTION -static const char *ext4_follow_link(struct dentry *dentry, void **cookie, struct nameidata *nd) +static const char *ext4_follow_link(struct dentry *dentry, void **cookie) { struct page *cpage = NULL; char *caddr, *paddr = NULL; diff --git a/fs/f2fs/namei.c b/fs/f2fs/namei.c index d2947937515e..cd05a7c91533 100644 --- a/fs/f2fs/namei.c +++ b/fs/f2fs/namei.c @@ -296,9 +296,9 @@ fail: return err; } -static const char *f2fs_follow_link(struct dentry *dentry, void **cookie, struct nameidata *nd) +static const char *f2fs_follow_link(struct dentry *dentry, void **cookie) { - const char *link = page_follow_link_light(dentry, cookie, nd); + const char *link = page_follow_link_light(dentry, cookie); if (!IS_ERR(link) && !*link) { /* this is broken symlink case */ page_put_link(dentry, *cookie); diff --git a/fs/fuse/dir.c b/fs/fuse/dir.c index f9cb260375cf..d5cdef8b7f3a 100644 --- a/fs/fuse/dir.c +++ b/fs/fuse/dir.c @@ -1365,7 +1365,7 @@ static int fuse_readdir(struct file *file, struct dir_context *ctx) return err; } -static const char *fuse_follow_link(struct dentry *dentry, void **cookie, struct nameidata *nd) +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); diff --git a/fs/gfs2/inode.c b/fs/gfs2/inode.c index f59390aebffb..3a1461de1551 100644 --- a/fs/gfs2/inode.c +++ b/fs/gfs2/inode.c @@ -1548,7 +1548,7 @@ out: * Returns: 0 on success or error code */ -static const char *gfs2_follow_link(struct dentry *dentry, void **cookie, 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; diff --git a/fs/hostfs/hostfs_kern.c b/fs/hostfs/hostfs_kern.c index f650ed661fab..7b6ed7a908f6 100644 --- a/fs/hostfs/hostfs_kern.c +++ b/fs/hostfs/hostfs_kern.c @@ -892,7 +892,7 @@ static const struct inode_operations hostfs_dir_iops = { .setattr = hostfs_setattr, }; -static const char *hostfs_follow_link(struct dentry *dentry, void **cookie, struct nameidata *nd) +static const char *hostfs_follow_link(struct dentry *dentry, void **cookie) { char *link = __getname(); if (link) { diff --git a/fs/hppfs/hppfs.c b/fs/hppfs/hppfs.c index b8f24d3b04ee..15a774eb5bbf 100644 --- a/fs/hppfs/hppfs.c +++ b/fs/hppfs/hppfs.c @@ -642,11 +642,11 @@ static int hppfs_readlink(struct dentry *dentry, char __user *buffer, buflen); } -static const char *hppfs_follow_link(struct dentry *dentry, void **cookie, 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, cookie, nd); + return d_inode(proc_dentry)->i_op->follow_link(proc_dentry, cookie); } static void hppfs_put_link(struct dentry *dentry, void *cookie) diff --git a/fs/kernfs/symlink.c b/fs/kernfs/symlink.c index 3c7e799974a2..366c5a17475e 100644 --- a/fs/kernfs/symlink.c +++ b/fs/kernfs/symlink.c @@ -112,7 +112,7 @@ static int kernfs_getlink(struct dentry *dentry, char *path) return error; } -static const char *kernfs_iop_follow_link(struct dentry *dentry, void **cookie, 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); diff --git a/fs/libfs.c b/fs/libfs.c index 0c83fde20dbd..c5f3373e326b 100644 --- a/fs/libfs.c +++ b/fs/libfs.c @@ -1091,7 +1091,7 @@ simple_nosetlease(struct file *filp, long arg, struct file_lock **flp, } EXPORT_SYMBOL(simple_nosetlease); -const char *simple_follow_link(struct dentry *dentry, void **cookie, struct nameidata *nd) +const char *simple_follow_link(struct dentry *dentry, void **cookie) { return d_inode(dentry)->i_link; } diff --git a/fs/namei.c b/fs/namei.c index b57400ca6a0f..f311f0369e3c 100644 --- a/fs/namei.c +++ b/fs/namei.c @@ -753,8 +753,9 @@ static inline void path_to_nameidata(const struct path *path, * Helper to directly jump to a known parsed path from ->follow_link, * caller must have taken a reference to path beforehand. */ -void nd_jump_link(struct nameidata *nd, struct path *path) +void nd_jump_link(struct path *path) { + struct nameidata *nd = current->nameidata; path_put(&nd->path); nd->path = *path; @@ -916,7 +917,7 @@ const char *get_link(struct nameidata *nd) nd->last_type = LAST_BIND; res = inode->i_link; if (!res) { - res = inode->i_op->follow_link(dentry, &last->cookie, nd); + res = inode->i_op->follow_link(dentry, &last->cookie); if (IS_ERR(res)) { out: path_put(&last->link); @@ -4485,12 +4486,12 @@ int generic_readlink(struct dentry *dentry, char __user *buffer, int buflen) int res; if (!link) { - link = dentry->d_inode->i_op->follow_link(dentry, &cookie, NULL); + link = dentry->d_inode->i_op->follow_link(dentry, &cookie); if (IS_ERR(link)) return PTR_ERR(link); } res = readlink_copy(buffer, buflen, link); - if (cookie && dentry->d_inode->i_op->put_link) + if (dentry->d_inode->i_op->put_link) dentry->d_inode->i_op->put_link(dentry, cookie); return res; } @@ -4523,7 +4524,7 @@ int page_readlink(struct dentry *dentry, char __user *buffer, int buflen) } EXPORT_SYMBOL(page_readlink); -const char *page_follow_link_light(struct dentry *dentry, void **cookie, struct nameidata *nd) +const char *page_follow_link_light(struct dentry *dentry, void **cookie) { struct page *page = NULL; char *res = page_getlink(dentry, &page); diff --git a/fs/nfs/symlink.c b/fs/nfs/symlink.c index c992b200ae7e..b6de433da5db 100644 --- a/fs/nfs/symlink.c +++ b/fs/nfs/symlink.c @@ -42,7 +42,7 @@ error: return -EIO; } -static const char *nfs_follow_link(struct dentry *dentry, void **cookie, struct nameidata *nd) +static const char *nfs_follow_link(struct dentry *dentry, void **cookie) { struct inode *inode = d_inode(dentry); struct page *page; diff --git a/fs/overlayfs/inode.c b/fs/overlayfs/inode.c index 235ad42afb57..9986833c9fcc 100644 --- a/fs/overlayfs/inode.c +++ b/fs/overlayfs/inode.c @@ -140,7 +140,7 @@ struct ovl_link_data { void *cookie; }; -static const char *ovl_follow_link(struct dentry *dentry, void **cookie, struct nameidata *nd) +static const char *ovl_follow_link(struct dentry *dentry, void **cookie) { struct dentry *realdentry; struct inode *realinode; @@ -160,7 +160,7 @@ static const char *ovl_follow_link(struct dentry *dentry, void **cookie, struct data->realdentry = realdentry; } - ret = realinode->i_op->follow_link(realdentry, cookie, nd); + ret = realinode->i_op->follow_link(realdentry, cookie); if (IS_ERR_OR_NULL(ret)) { kfree(data); return ret; diff --git a/fs/proc/base.c b/fs/proc/base.c index 52652f86b187..286a422f440e 100644 --- a/fs/proc/base.c +++ b/fs/proc/base.c @@ -1380,7 +1380,7 @@ static int proc_exe_link(struct dentry *dentry, struct path *exe_path) return -ENOENT; } -static const char *proc_pid_follow_link(struct dentry *dentry, void **cookie, 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 const char *proc_pid_follow_link(struct dentry *dentry, void **cookie, st if (error) goto out; - nd_jump_link(nd, &path); + nd_jump_link(&path); return NULL; out: return ERR_PTR(error); diff --git a/fs/proc/inode.c b/fs/proc/inode.c index acd51d75387d..eb35874fe09c 100644 --- a/fs/proc/inode.c +++ b/fs/proc/inode.c @@ -393,7 +393,7 @@ static const struct file_operations proc_reg_file_ops_no_compat = { }; #endif -static const char *proc_follow_link(struct dentry *dentry, void **cookie, 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))) diff --git a/fs/proc/namespaces.c b/fs/proc/namespaces.c index 10d24dd096e8..f6e8354b8cea 100644 --- a/fs/proc/namespaces.c +++ b/fs/proc/namespaces.c @@ -30,7 +30,7 @@ static const struct proc_ns_operations *ns_entries[] = { &mntns_operations, }; -static const char *proc_ns_follow_link(struct dentry *dentry, void **cookie, 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 const char *proc_ns_follow_link(struct dentry *dentry, void **cookie, str 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; diff --git a/fs/proc/self.c b/fs/proc/self.c index ad333946b53a..113b8d061fc0 100644 --- a/fs/proc/self.c +++ b/fs/proc/self.c @@ -18,7 +18,7 @@ static int proc_self_readlink(struct dentry *dentry, char __user *buffer, return readlink_copy(buffer, buflen, tmp); } -static const char *proc_self_follow_link(struct dentry *dentry, void **cookie, 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); diff --git a/fs/proc/thread_self.c b/fs/proc/thread_self.c index 85c96e0d7aaa..947b0f4fd0a1 100644 --- a/fs/proc/thread_self.c +++ b/fs/proc/thread_self.c @@ -19,7 +19,7 @@ static int proc_thread_self_readlink(struct dentry *dentry, char __user *buffer, return readlink_copy(buffer, buflen, tmp); } -static const char *proc_thread_self_follow_link(struct dentry *dentry, void **cookie, 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); diff --git a/fs/xfs/xfs_iops.c b/fs/xfs/xfs_iops.c index 26c4dcb1ef56..7f51f39f8acc 100644 --- a/fs/xfs/xfs_iops.c +++ b/fs/xfs/xfs_iops.c @@ -416,8 +416,7 @@ xfs_vn_rename( STATIC const char * xfs_vn_follow_link( struct dentry *dentry, - void **cookie, - struct nameidata *nd) + void **cookie) { char *link; int error = -ENOMEM; diff --git a/include/linux/fs.h b/include/linux/fs.h index 9ab934113a28..ed7c9f298759 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -1608,7 +1608,7 @@ struct file_operations { struct inode_operations { struct dentry * (*lookup) (struct inode *,struct dentry *, unsigned int); - const char * (*follow_link) (struct dentry *, void **, struct nameidata *); + const char * (*follow_link) (struct dentry *, void **); int (*permission) (struct inode *, int); struct posix_acl * (*get_acl)(struct inode *, int); @@ -2705,7 +2705,7 @@ 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 const char *page_follow_link_light(struct dentry *, void **, struct nameidata *); +extern const char *page_follow_link_light(struct dentry *, void **); extern void page_put_link(struct dentry *, void *); extern int __page_symlink(struct inode *inode, const char *symname, int len, int nofs); @@ -2722,7 +2722,7 @@ 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 **, struct nameidata *); +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 *); diff --git a/include/linux/namei.h b/include/linux/namei.h index 3a6cc9651712..d756304aa09b 100644 --- a/include/linux/namei.h +++ b/include/linux/namei.h @@ -72,7 +72,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_jump_link(struct path *path); static inline void nd_terminate_link(void *name, size_t len, size_t maxlen) { diff --git a/mm/shmem.c b/mm/shmem.c index d1693dcb4285..e02682267046 100644 --- a/mm/shmem.c +++ b/mm/shmem.c @@ -2475,7 +2475,7 @@ static int shmem_symlink(struct inode *dir, struct dentry *dentry, const char *s return 0; } -static const char *shmem_follow_link(struct dentry *dentry, void **cookie, 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); -- cgit v1.2.3 From 5f2c4179e129bdc47870a81a65d0aff85aa18293 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Thu, 7 May 2015 11:14:26 -0400 Subject: switch ->put_link() from dentry to inode only one instance looks at that argument at all; that sole exception wants inode rather than dentry. Signed-off-by: Al Viro --- Documentation/filesystems/Locking | 2 +- Documentation/filesystems/vfs.txt | 2 +- drivers/staging/lustre/lustre/llite/symlink.c | 2 +- fs/configfs/symlink.c | 2 +- fs/f2fs/namei.c | 2 +- fs/fuse/dir.c | 2 +- fs/hostfs/hostfs_kern.c | 2 +- fs/hppfs/hppfs.c | 8 ++++---- fs/kernfs/symlink.c | 2 +- fs/libfs.c | 2 +- fs/namei.c | 13 +++++++------ fs/overlayfs/inode.c | 4 ++-- fs/proc/inode.c | 2 +- include/linux/fs.h | 6 +++--- mm/shmem.c | 2 +- 15 files changed, 27 insertions(+), 26 deletions(-) (limited to 'Documentation') diff --git a/Documentation/filesystems/Locking b/Documentation/filesystems/Locking index 5b5b4f54c033..6a34a0f4d37c 100644 --- a/Documentation/filesystems/Locking +++ b/Documentation/filesystems/Locking @@ -51,7 +51,7 @@ prototypes: struct inode *, struct dentry *, unsigned int); int (*readlink) (struct dentry *, char __user *,int); const char *(*follow_link) (struct dentry *, void **); - void (*put_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); diff --git a/Documentation/filesystems/vfs.txt b/Documentation/filesystems/vfs.txt index 0dec8c880be6..542d9352d0f2 100644 --- a/Documentation/filesystems/vfs.txt +++ b/Documentation/filesystems/vfs.txt @@ -351,7 +351,7 @@ struct inode_operations { struct inode *, struct dentry *, unsigned int); int (*readlink) (struct dentry *, char __user *,int); const char *(*follow_link) (struct dentry *, void **); - void (*put_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 *); diff --git a/drivers/staging/lustre/lustre/llite/symlink.c b/drivers/staging/lustre/lustre/llite/symlink.c index f3be3bf0f66f..69b203651905 100644 --- a/drivers/staging/lustre/lustre/llite/symlink.c +++ b/drivers/staging/lustre/lustre/llite/symlink.c @@ -141,7 +141,7 @@ static const char *ll_follow_link(struct dentry *dentry, void **cookie) return symname; } -static void ll_put_link(struct dentry *dentry, void *cookie) +static void ll_put_link(struct inode *unused, void *cookie) { ptlrpc_req_finished(cookie); } diff --git a/fs/configfs/symlink.c b/fs/configfs/symlink.c index 0ace75649009..bc464c26e00e 100644 --- a/fs/configfs/symlink.c +++ b/fs/configfs/symlink.c @@ -296,7 +296,7 @@ static const char *configfs_follow_link(struct dentry *dentry, void **cookie) return ERR_PTR(error); } -static void configfs_put_link(struct dentry *dentry, void *cookie) +static void configfs_put_link(struct inode *unused, void *cookie) { free_page((unsigned long)cookie); } diff --git a/fs/f2fs/namei.c b/fs/f2fs/namei.c index cd05a7c91533..71765d062914 100644 --- a/fs/f2fs/namei.c +++ b/fs/f2fs/namei.c @@ -301,7 +301,7 @@ static const char *f2fs_follow_link(struct dentry *dentry, void **cookie) const char *link = page_follow_link_light(dentry, cookie); if (!IS_ERR(link) && !*link) { /* this is broken symlink case */ - page_put_link(dentry, *cookie); + page_put_link(NULL, *cookie); link = ERR_PTR(-ENOENT); } return link; diff --git a/fs/fuse/dir.c b/fs/fuse/dir.c index d5cdef8b7f3a..9e704c124392 100644 --- a/fs/fuse/dir.c +++ b/fs/fuse/dir.c @@ -1395,7 +1395,7 @@ static const char *fuse_follow_link(struct dentry *dentry, void **cookie) return link; } -static void fuse_put_link(struct dentry *dentry, void *cookie) +static void fuse_put_link(struct inode *unused, void *cookie) { free_page((unsigned long) cookie); } diff --git a/fs/hostfs/hostfs_kern.c b/fs/hostfs/hostfs_kern.c index 7b6ed7a908f6..4a437ab5f296 100644 --- a/fs/hostfs/hostfs_kern.c +++ b/fs/hostfs/hostfs_kern.c @@ -915,7 +915,7 @@ static const char *hostfs_follow_link(struct dentry *dentry, void **cookie) return *cookie = link; } -static void hostfs_put_link(struct dentry *dentry, void *cookie) +static void hostfs_put_link(struct inode *unused, void *cookie) { __putname(cookie); } diff --git a/fs/hppfs/hppfs.c b/fs/hppfs/hppfs.c index 15a774eb5bbf..2867837909a9 100644 --- a/fs/hppfs/hppfs.c +++ b/fs/hppfs/hppfs.c @@ -649,12 +649,12 @@ static const char *hppfs_follow_link(struct dentry *dentry, void **cookie) return d_inode(proc_dentry)->i_op->follow_link(proc_dentry, cookie); } -static void hppfs_put_link(struct dentry *dentry, 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, 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 = { diff --git a/fs/kernfs/symlink.c b/fs/kernfs/symlink.c index 366c5a17475e..f6aa2e5a76b4 100644 --- a/fs/kernfs/symlink.c +++ b/fs/kernfs/symlink.c @@ -126,7 +126,7 @@ static const char *kernfs_iop_follow_link(struct dentry *dentry, void **cookie) return *cookie = (char *)page; } -static void kernfs_iop_put_link(struct dentry *dentry, void *cookie) +static void kernfs_iop_put_link(struct inode *unused, void *cookie) { free_page((unsigned long)cookie); } diff --git a/fs/libfs.c b/fs/libfs.c index c5f3373e326b..01c337b0fec8 100644 --- a/fs/libfs.c +++ b/fs/libfs.c @@ -1024,7 +1024,7 @@ 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, void *cookie) +void kfree_put_link(struct inode *unused, void *cookie) { kfree(cookie); } diff --git a/fs/namei.c b/fs/namei.c index 0fa7af23cff6..43034046a0e1 100644 --- a/fs/namei.c +++ b/fs/namei.c @@ -749,7 +749,7 @@ static inline void put_link(struct nameidata *nd) struct saved *last = nd->stack + --nd->depth; struct inode *inode = last->inode; if (last->cookie && inode->i_op->put_link) - inode->i_op->put_link(last->link.dentry, last->cookie); + inode->i_op->put_link(inode, last->cookie); path_put(&last->link); } @@ -4444,17 +4444,18 @@ EXPORT_SYMBOL(readlink_copy); int generic_readlink(struct dentry *dentry, char __user *buffer, int buflen) { void *cookie; - const char *link = dentry->d_inode->i_link; + struct inode *inode = d_inode(dentry); + const char *link = inode->i_link; int res; if (!link) { - link = dentry->d_inode->i_op->follow_link(dentry, &cookie); + link = inode->i_op->follow_link(dentry, &cookie); if (IS_ERR(link)) return PTR_ERR(link); } res = readlink_copy(buffer, buflen, link); - if (dentry->d_inode->i_op->put_link) - dentry->d_inode->i_op->put_link(dentry, cookie); + if (inode->i_op->put_link) + inode->i_op->put_link(inode, cookie); return res; } EXPORT_SYMBOL(generic_readlink); @@ -4496,7 +4497,7 @@ const char *page_follow_link_light(struct dentry *dentry, void **cookie) } EXPORT_SYMBOL(page_follow_link_light); -void page_put_link(struct dentry *dentry, void *cookie) +void page_put_link(struct inode *unused, void *cookie) { struct page *page = cookie; kunmap(page); diff --git a/fs/overlayfs/inode.c b/fs/overlayfs/inode.c index 9986833c9fcc..308379b2d0b2 100644 --- a/fs/overlayfs/inode.c +++ b/fs/overlayfs/inode.c @@ -174,7 +174,7 @@ static const char *ovl_follow_link(struct dentry *dentry, void **cookie) return ret; } -static void ovl_put_link(struct dentry *dentry, void *c) +static void ovl_put_link(struct inode *unused, void *c) { struct inode *realinode; struct ovl_link_data *data = c; @@ -183,7 +183,7 @@ static void ovl_put_link(struct dentry *dentry, void *c) return; realinode = data->realdentry->d_inode; - realinode->i_op->put_link(data->realdentry, data->cookie); + realinode->i_op->put_link(realinode, data->cookie); kfree(data); } diff --git a/fs/proc/inode.c b/fs/proc/inode.c index eb35874fe09c..afe232b9df6e 100644 --- a/fs/proc/inode.c +++ b/fs/proc/inode.c @@ -402,7 +402,7 @@ static const char *proc_follow_link(struct dentry *dentry, void **cookie) return pde->data; } -static void proc_put_link(struct dentry *dentry, void *p) +static void proc_put_link(struct inode *unused, void *p) { unuse_pde(p); } diff --git a/include/linux/fs.h b/include/linux/fs.h index ed7c9f298759..f21e3328f991 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -1613,7 +1613,7 @@ struct inode_operations { struct posix_acl * (*get_acl)(struct inode *, int); int (*readlink) (struct dentry *, char __user *,int); - void (*put_link) (struct dentry *, void *); + void (*put_link) (struct inode *, void *); int (*create) (struct inode *,struct dentry *, umode_t, bool); int (*link) (struct dentry *,struct inode *,struct dentry *); @@ -2706,12 +2706,12 @@ 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 const char *page_follow_link_light(struct dentry *, void **); -extern void page_put_link(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 *, void *); +extern void kfree_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); diff --git a/mm/shmem.c b/mm/shmem.c index e02682267046..a59087edf728 100644 --- a/mm/shmem.c +++ b/mm/shmem.c @@ -2486,7 +2486,7 @@ static const char *shmem_follow_link(struct dentry *dentry, void **cookie) return kmap(page); } -static void shmem_put_link(struct dentry *dentry, void *cookie) +static void shmem_put_link(struct inode *unused, void *cookie) { struct page *page = cookie; kunmap(page); -- cgit v1.2.3 From 203bc643db59e2538e9a3f19be1636cdfd2bb2db Mon Sep 17 00:00:00 2001 From: Al Viro Date: Mon, 11 May 2015 08:29:30 -0400 Subject: update Documentation/filesystems/ regarding the follow_link/put_link changes Signed-off-by: Al Viro --- Documentation/filesystems/porting | 17 +++++++++++++++++ Documentation/filesystems/vfs.txt | 18 ++++++++++-------- 2 files changed, 27 insertions(+), 8 deletions(-) (limited to 'Documentation') diff --git a/Documentation/filesystems/porting b/Documentation/filesystems/porting index e69274de8d0c..3eae250254d5 100644 --- a/Documentation/filesystems/porting +++ b/Documentation/filesystems/porting @@ -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. diff --git a/Documentation/filesystems/vfs.txt b/Documentation/filesystems/vfs.txt index 542d9352d0f2..b403b29ef710 100644 --- a/Documentation/filesystems/vfs.txt +++ b/Documentation/filesystems/vfs.txt @@ -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. -- cgit v1.2.3 From 99ff6cf0e67ada025ba8054a055862383355ec0e Mon Sep 17 00:00:00 2001 From: NeilBrown Date: Mon, 23 Mar 2015 13:37:38 +1100 Subject: Documentation: remove outdated information from automount-support.txt The guidelines for adding automount support to a filesystem in filesystems/automount-support.txt is out or date. filesystems/autofs4.txt contains more current text, so replace the out-of-date content with a reference to that. Signed-off-by: NeilBrown Signed-off-by: Al Viro --- Documentation/filesystems/automount-support.txt | 51 +++++++------------------ 1 file changed, 13 insertions(+), 38 deletions(-) (limited to 'Documentation') diff --git a/Documentation/filesystems/automount-support.txt b/Documentation/filesystems/automount-support.txt index 7cac200e2a85..7eb762eb3136 100644 --- a/Documentation/filesystems/automount-support.txt +++ b/Documentation/filesystems/automount-support.txt @@ -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. -- cgit v1.2.3