@@ -125,6 +125,9 @@ static void *ll_follow_link(struct dentry *dentry, struct nameidata *nd)
int rc;
char *symname = NULL;
+ if (nd_is_rcu(nd))
+ return PTR_ERR(-ECHILD);
+
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.
@@ -1281,7 +1281,11 @@ done:
static void *v9fs_vfs_follow_link(struct dentry *dentry, struct nameidata *nd)
{
int len = 0;
- char *link = __getname();
+ char *link;
+
+ if (nd_is_rcu(nd))
+ return ERR_PTR(-ECHILD);
+ link = __getname();
p9_debug(P9_DEBUG_VFS, "%pd\n", dentry);
@@ -914,9 +914,12 @@ v9fs_vfs_follow_link_dotl(struct dentry *dentry, struct nameidata *nd)
{
int retval;
struct p9_fid *fid;
- char *link = __getname();
+ char *link;
char *target;
+ if (nd_is_rcu(nd))
+ return ERR_PTR(-ECHILD);
+ link = __getname();
p9_debug(P9_DEBUG_VFS, "%pd\n", dentry);
if (!link) {
@@ -477,6 +477,8 @@ befs_follow_link(struct dentry *dentry, struct nameidata *nd)
befs_off_t len = data->size;
char *link;
+ if (nd_is_rcu(nd))
+ return ERR_PTR(-ECHILD);
if (len == 0) {
befs_error(sb, "Long symlink with illegal length");
link = ERR_PTR(-EIO);
@@ -639,6 +639,8 @@ cifs_follow_link(struct dentry *direntry, struct nameidata *nd)
struct cifs_tcon *tcon;
struct TCP_Server_Info *server;
+ if (nd_is_rcu(nd))
+ return ERR_PTR(-ECHILD);
xid = get_xid();
tlink = cifs_sb_tlink(cifs_sb);
@@ -282,7 +282,12 @@ static int configfs_getlink(struct dentry *dentry, char * path)
static void *configfs_follow_link(struct dentry *dentry, struct nameidata *nd)
{
int error = -ENOMEM;
- unsigned long page = get_zeroed_page(GFP_KERNEL);
+ unsigned long page;
+
+ if (nd_is_rcu(nd))
+ return ERR_PTR(-ECHILD);
+
+ page = get_zeroed_page(GFP_KERNEL);
if (page) {
error = configfs_getlink(dentry, (char *)page);
@@ -678,7 +678,12 @@ out:
static void *ecryptfs_follow_link(struct dentry *dentry, struct nameidata *nd)
{
size_t len;
- char *buf = ecryptfs_readlink_lower(dentry, &len);
+ char *buf;
+
+ if (nd_is_rcu(nd))
+ return ERR_PTR(-ECHILD);
+
+ buf = ecryptfs_readlink_lower(dentry, &len);
if (IS_ERR(buf))
goto out;
fsstack_copy_attr_atime(dentry->d_inode,
@@ -1402,6 +1402,8 @@ static void free_link(char *link)
static void *fuse_follow_link(struct dentry *dentry, struct nameidata *nd)
{
+ if (nd_is_rcu(nd))
+ return ERR_PTR(-ECHILD);
nd_set_link(nd, read_link(dentry));
return NULL;
}
@@ -1557,6 +1557,8 @@ static void *gfs2_follow_link(struct dentry *dentry, struct nameidata *nd)
char *buf;
int error;
+ if (nd_is_rcu(nd))
+ return ERR_PTR(-ECHILD);
gfs2_holder_init(ip->i_gl, LM_ST_SHARED, 0, &i_gh);
error = gfs2_glock_nq(&i_gh);
if (error) {
@@ -884,7 +884,12 @@ static const struct inode_operations hostfs_dir_iops = {
static void *hostfs_follow_link(struct dentry *dentry, struct nameidata *nd)
{
- char *link = __getname();
+ char *link;
+
+ if (nd_is_rcu(nd))
+ return ERR_PTR(-ECHILD);
+
+ link = __getname();
if (link) {
char *path = dentry_name(dentry);
int err = -ENOMEM;
@@ -115,7 +115,12 @@ static int kernfs_getlink(struct dentry *dentry, char *path)
static void *kernfs_iop_follow_link(struct dentry *dentry, struct nameidata *nd)
{
int error = -ENOMEM;
- unsigned long page = get_zeroed_page(GFP_KERNEL);
+ unsigned long page;
+
+ if (nd_is_rcu(nd))
+ return ERR_PTR(-ECHILD);
+
+ page = get_zeroed_page(GFP_KERNEL);
if (page) {
error = kernfs_getlink(dentry, (char *) page);
if (error < 0)
@@ -4475,6 +4475,8 @@ EXPORT_SYMBOL(page_readlink);
void *page_follow_link_light(struct dentry *dentry, struct nameidata *nd)
{
struct page *page = NULL;
+ if (nd->flags & LOOKUP_RCU)
+ return ERR_PTR(-ECHILD);
nd_set_link(nd, page_getlink(dentry, &page));
return page;
}
@@ -4542,3 +4544,9 @@ const struct inode_operations page_symlink_inode_operations = {
.put_link = page_put_link,
};
EXPORT_SYMBOL(page_symlink_inode_operations);
+
+int nd_is_rcu(struct nameidata *nd)
+{
+ return nd->flags & LOOKUP_RCU;
+}
+EXPORT_SYMBOL(nd_is_rcu);
@@ -49,6 +49,8 @@ static void *nfs_follow_link(struct dentry *dentry, struct nameidata *nd)
struct page *page;
void *err;
+ if (nd_is_rcu(nd))
+ return ERR_PTR(-ECHILD);
err = ERR_PTR(nfs_revalidate_mapping(inode, inode->i_mapping));
if (err)
goto read_failed;
@@ -8,6 +8,7 @@
*/
#include <linux/fs.h>
+#include <linux/namei.h>
#include <linux/slab.h>
#include <linux/xattr.h>
#include "overlayfs.h"
@@ -146,6 +147,8 @@ static void *ovl_follow_link(struct dentry *dentry, struct nameidata *nd)
struct dentry *realdentry;
struct inode *realinode;
+ if (nd_is_rcu(nd))
+ return ERR_PTR(-ECHILD);
realdentry = ovl_dentry_real(dentry);
realinode = realdentry->d_inode;
@@ -1377,6 +1377,8 @@ static void *proc_pid_follow_link(struct dentry *dentry, struct nameidata *nd)
struct path path;
int error = -EACCES;
+ if (nd_is_rcu(nd))
+ return ERR_PTR(-ECHILD);
/* Are we allowed to snoop on the tasks file descriptors? */
if (!proc_fd_access_allowed(inode))
goto out;
@@ -38,6 +38,9 @@ static void *proc_ns_follow_link(struct dentry *dentry, struct nameidata *nd)
struct path ns_path;
void *error = ERR_PTR(-EACCES);
+ if (nd_is_rcu(nd))
+ return ERR_PTR(-ECHILD);
+
task = get_proc_task(inode);
if (!task)
return error;
@@ -24,6 +24,10 @@ static void *proc_self_follow_link(struct dentry *dentry, struct nameidata *nd)
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 (nd_is_rcu(nd))
+ return ERR_PTR(-ECHILD);
+
if (tgid) {
/* 11 for max length of signed int in decimal + NULL term */
name = kmalloc(12, GFP_KERNEL);
@@ -26,6 +26,10 @@ static void *proc_thread_self_follow_link(struct dentry *dentry, struct nameidat
pid_t tgid = task_tgid_nr_ns(current, ns);
pid_t pid = task_pid_nr_ns(current, ns);
char *name = ERR_PTR(-ENOENT);
+
+ if (nd_is_rcu(nd))
+ return ERR_PTR(-ECHILD);
+
if (pid) {
name = kmalloc(PROC_NUMBUF + 6 + PROC_NUMBUF, GFP_KERNEL);
if (!name)
@@ -417,6 +417,8 @@ xfs_vn_follow_link(
char *link;
int error = -ENOMEM;
+ if (nd_is_rcu(nd))
+ return ERR_PTR(-ECHILD);
link = kmalloc(MAXPATHLEN+1, GFP_KERNEL);
if (!link)
goto out_err;
@@ -2167,6 +2167,7 @@ extern struct filename *getname_flags(const char __user *, int, int *);
extern struct filename *getname(const char __user *);
extern struct filename *getname_kernel(const char *);
extern void putname(struct filename *name);
+extern int nd_is_rcu(struct nameidata *nd);
enum {
FILE_CREATED = 1,
@@ -2483,7 +2483,11 @@ static void *shmem_follow_short_symlink(struct dentry *dentry, struct nameidata
static void *shmem_follow_link(struct dentry *dentry, struct nameidata *nd)
{
struct page *page = NULL;
- int error = shmem_getpage(dentry->d_inode, 0, &page, SGP_READ, NULL);
+ int error;
+
+ if (nd_is_rcu(nd))
+ return ERR_PTR(-ECHILD);
+ error = shmem_getpage(dentry->d_inode, 0, &page, SGP_READ, NULL);
nd_set_link(nd, error ? ERR_PTR(error) : kmap(page));
if (page)
unlock_page(page);
In preparation for supporting ->follow_link in RCU-walk, make sure all ->follow_link handers which are not atomic will fail if LOOKUP_RCU is set. Later patches will make some of these handle LOOKUP_RCU more gracefully. This is current achieved by introducing a new function "nd_is_rcu" to check if a nameidata has LOOKUP_RCU set. There must be a better way. Signed-off-by: NeilBrown <neilb@suse.de> --- drivers/staging/lustre/lustre/llite/symlink.c | 3 +++ fs/9p/vfs_inode.c | 6 +++++- fs/9p/vfs_inode_dotl.c | 5 ++++- fs/befs/linuxvfs.c | 2 ++ fs/cifs/link.c | 2 ++ fs/configfs/symlink.c | 7 ++++++- fs/ecryptfs/inode.c | 7 ++++++- fs/fuse/dir.c | 2 ++ fs/gfs2/inode.c | 2 ++ fs/hostfs/hostfs_kern.c | 7 ++++++- fs/kernfs/symlink.c | 7 ++++++- fs/namei.c | 8 ++++++++ fs/nfs/symlink.c | 2 ++ fs/overlayfs/inode.c | 3 +++ fs/proc/base.c | 2 ++ fs/proc/namespaces.c | 3 +++ fs/proc/self.c | 4 ++++ fs/proc/thread_self.c | 4 ++++ fs/xfs/xfs_iops.c | 2 ++ include/linux/fs.h | 1 + mm/shmem.c | 6 +++++- 21 files changed, 78 insertions(+), 7 deletions(-) -- To unsubscribe from this list: send the line "unsubscribe linux-fsdevel" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html