summaryrefslogtreecommitdiff
path: root/fs
diff options
context:
space:
mode:
Diffstat (limited to 'fs')
-rw-r--r--fs/9p/vfs_inode.c9
-rw-r--r--fs/9p/vfs_inode_dotl.c9
-rw-r--r--fs/affs/symlink.c1
-rw-r--r--fs/autofs4/symlink.c3
-rw-r--r--fs/btrfs/inode.c1
-rw-r--r--fs/cifs/cifsfs.c1
-rw-r--r--fs/cifs/cifsfs.h3
-rw-r--r--fs/cifs/link.c6
-rw-r--r--fs/coda/cnode.c1
-rw-r--r--fs/configfs/symlink.c17
-rw-r--r--fs/ecryptfs/inode.c7
-rw-r--r--fs/ext2/symlink.c1
-rw-r--r--fs/ext4/symlink.c8
-rw-r--r--fs/f2fs/namei.c16
-rw-r--r--fs/fuse/dir.c6
-rw-r--r--fs/gfs2/inode.c8
-rw-r--r--fs/hostfs/hostfs_kern.c16
-rw-r--r--fs/jfs/symlink.c1
-rw-r--r--fs/kernfs/symlink.c19
-rw-r--r--fs/libfs.c9
-rw-r--r--fs/minix/inode.c1
-rw-r--r--fs/namei.c63
-rw-r--r--fs/ncpfs/inode.c1
-rw-r--r--fs/nfs/symlink.c6
-rw-r--r--fs/nilfs2/namei.c1
-rw-r--r--fs/ocfs2/symlink.c1
-rw-r--r--fs/overlayfs/inode.c45
-rw-r--r--fs/proc/base.c8
-rw-r--r--fs/proc/inode.c16
-rw-r--r--fs/proc/namespaces.c3
-rw-r--r--fs/proc/self.c7
-rw-r--r--fs/proc/thread_self.c7
-rw-r--r--fs/reiserfs/namei.c1
-rw-r--r--fs/squashfs/symlink.c1
-rw-r--r--fs/sysv/inode.c1
-rw-r--r--fs/xfs/xfs_iops.c6
36 files changed, 130 insertions, 180 deletions
diff --git a/fs/9p/vfs_inode.c b/fs/9p/vfs_inode.c
index 8ba5a897fc0a..f928f8702f4c 100644
--- a/fs/9p/vfs_inode.c
+++ b/fs/9p/vfs_inode.c
@@ -1226,11 +1226,12 @@ ino_t v9fs_qid2ino(struct p9_qid *qid)
* v9fs_vfs_get_link - follow a symlink path
* @dentry: dentry for symlink
* @inode: inode for symlink
- * @cookie: place to pass the data to put_link()
+ * @done: delayed call for when we are done with the return value
*/
static const char *v9fs_vfs_get_link(struct dentry *dentry,
- struct inode *inode, void **cookie)
+ struct inode *inode,
+ struct delayed_call *done)
{
struct v9fs_session_info *v9ses;
struct p9_fid *fid;
@@ -1266,7 +1267,8 @@ static const char *v9fs_vfs_get_link(struct dentry *dentry,
p9stat_free(st);
kfree(st);
- return *cookie = res;
+ set_delayed_call(done, kfree_link, res);
+ return res;
}
/**
@@ -1460,7 +1462,6 @@ static const struct inode_operations v9fs_file_inode_operations = {
static const struct inode_operations v9fs_symlink_inode_operations = {
.readlink = generic_readlink,
.get_link = v9fs_vfs_get_link,
- .put_link = kfree_put_link,
.getattr = v9fs_vfs_getattr,
.setattr = v9fs_vfs_setattr,
};
diff --git a/fs/9p/vfs_inode_dotl.c b/fs/9p/vfs_inode_dotl.c
index 0cc105d804dd..a34702c998f5 100644
--- a/fs/9p/vfs_inode_dotl.c
+++ b/fs/9p/vfs_inode_dotl.c
@@ -902,12 +902,13 @@ error:
* v9fs_vfs_get_link_dotl - follow a symlink path
* @dentry: dentry for symlink
* @inode: inode for symlink
- * @cookie: place to pass the data to put_link()
+ * @done: destructor for return value
*/
static const char *
v9fs_vfs_get_link_dotl(struct dentry *dentry,
- struct inode *inode, void **cookie)
+ struct inode *inode,
+ struct delayed_call *done)
{
struct p9_fid *fid;
char *target;
@@ -924,7 +925,8 @@ v9fs_vfs_get_link_dotl(struct dentry *dentry,
retval = p9_client_readlink(fid, &target);
if (retval)
return ERR_PTR(retval);
- return *cookie = target;
+ set_delayed_call(done, kfree_link, target);
+ return target;
}
int v9fs_refresh_inode_dotl(struct p9_fid *fid, struct inode *inode)
@@ -991,7 +993,6 @@ const struct inode_operations v9fs_file_inode_operations_dotl = {
const struct inode_operations v9fs_symlink_inode_operations_dotl = {
.readlink = generic_readlink,
.get_link = v9fs_vfs_get_link_dotl,
- .put_link = kfree_put_link,
.getattr = v9fs_vfs_getattr_dotl,
.setattr = v9fs_vfs_setattr_dotl,
.setxattr = generic_setxattr,
diff --git a/fs/affs/symlink.c b/fs/affs/symlink.c
index 39d1194445e1..69b03dbb792f 100644
--- a/fs/affs/symlink.c
+++ b/fs/affs/symlink.c
@@ -72,6 +72,5 @@ const struct address_space_operations affs_symlink_aops = {
const struct inode_operations affs_symlink_inode_operations = {
.readlink = generic_readlink,
.get_link = page_get_link,
- .put_link = page_put_link,
.setattr = affs_notify_change,
};
diff --git a/fs/autofs4/symlink.c b/fs/autofs4/symlink.c
index 39e6f0bdf8e3..84e037d1d129 100644
--- a/fs/autofs4/symlink.c
+++ b/fs/autofs4/symlink.c
@@ -13,7 +13,8 @@
#include "autofs_i.h"
static const char *autofs4_get_link(struct dentry *dentry,
- struct inode *inode, void **cookie)
+ struct inode *inode,
+ struct delayed_call *done)
{
struct autofs_sb_info *sbi;
struct autofs_info *ino;
diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c
index 3d4aa69f1e0c..1a41a65fd2ff 100644
--- a/fs/btrfs/inode.c
+++ b/fs/btrfs/inode.c
@@ -10097,7 +10097,6 @@ static const struct inode_operations btrfs_special_inode_operations = {
static const struct inode_operations btrfs_symlink_inode_operations = {
.readlink = generic_readlink,
.get_link = page_get_link,
- .put_link = page_put_link,
.getattr = btrfs_getattr,
.setattr = btrfs_setattr,
.permission = btrfs_permission,
diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c
index 4593f41678ef..90e4e2b398b6 100644
--- a/fs/cifs/cifsfs.c
+++ b/fs/cifs/cifsfs.c
@@ -901,7 +901,6 @@ const struct inode_operations cifs_file_inode_ops = {
const struct inode_operations cifs_symlink_inode_ops = {
.readlink = generic_readlink,
.get_link = cifs_get_link,
- .put_link = kfree_put_link,
.permission = cifs_permission,
/* BB add the following two eventually */
/* revalidate: cifs_revalidate,
diff --git a/fs/cifs/cifsfs.h b/fs/cifs/cifsfs.h
index 6886328cf3c4..26a1187d4323 100644
--- a/fs/cifs/cifsfs.h
+++ b/fs/cifs/cifsfs.h
@@ -120,7 +120,8 @@ extern struct vfsmount *cifs_dfs_d_automount(struct path *path);
#endif
/* Functions related to symlinks */
-extern const char *cifs_get_link(struct dentry *, struct inode *, void **);
+extern const char *cifs_get_link(struct dentry *, struct inode *,
+ struct delayed_call *);
extern int cifs_symlink(struct inode *inode, struct dentry *direntry,
const char *symname);
extern int cifs_removexattr(struct dentry *, const char *);
diff --git a/fs/cifs/link.c b/fs/cifs/link.c
index 6f2439b508b5..062c2375549a 100644
--- a/fs/cifs/link.c
+++ b/fs/cifs/link.c
@@ -627,7 +627,8 @@ cifs_hl_exit:
}
const char *
-cifs_get_link(struct dentry *direntry, struct inode *inode, void **cookie)
+cifs_get_link(struct dentry *direntry, struct inode *inode,
+ struct delayed_call *done)
{
int rc = -ENOMEM;
unsigned int xid;
@@ -680,7 +681,8 @@ cifs_get_link(struct dentry *direntry, struct inode *inode, void **cookie)
kfree(target_path);
return ERR_PTR(rc);
}
- return *cookie = target_path;
+ set_delayed_call(done, kfree_link, target_path);
+ return target_path;
}
int
diff --git a/fs/coda/cnode.c b/fs/coda/cnode.c
index f18139c7690a..1bfb7ba4e85e 100644
--- a/fs/coda/cnode.c
+++ b/fs/coda/cnode.c
@@ -19,7 +19,6 @@ static inline int coda_fideq(struct CodaFid *fid1, struct CodaFid *fid2)
static const struct inode_operations coda_symlink_inode_operations = {
.readlink = generic_readlink,
.get_link = page_get_link,
- .put_link = page_put_link,
.setattr = coda_setattr,
};
diff --git a/fs/configfs/symlink.c b/fs/configfs/symlink.c
index e9de962e518d..db6d69289608 100644
--- a/fs/configfs/symlink.c
+++ b/fs/configfs/symlink.c
@@ -280,31 +280,32 @@ static int configfs_getlink(struct dentry *dentry, char * path)
}
static const char *configfs_get_link(struct dentry *dentry,
- struct inode *inode, void **cookie)
+ struct inode *inode,
+ struct delayed_call *done)
{
- char *page;
+ char *body;
int error;
if (!dentry)
return ERR_PTR(-ECHILD);
- page = kzalloc(PAGE_SIZE, GFP_KERNEL);
- if (!page)
+ body = kzalloc(PAGE_SIZE, GFP_KERNEL);
+ if (!body)
return ERR_PTR(-ENOMEM);
- error = configfs_getlink(dentry, page);
+ error = configfs_getlink(dentry, body);
if (!error) {
- return *cookie = page;
+ set_delayed_call(done, kfree_link, body);
+ return body;
}
- kfree(page);
+ kfree(body);
return ERR_PTR(error);
}
const struct inode_operations configfs_symlink_inode_operations = {
.get_link = configfs_get_link,
.readlink = generic_readlink,
- .put_link = kfree_put_link,
.setattr = configfs_setattr,
};
diff --git a/fs/ecryptfs/inode.c b/fs/ecryptfs/inode.c
index 5a05559cb23d..a4dddc61594c 100644
--- a/fs/ecryptfs/inode.c
+++ b/fs/ecryptfs/inode.c
@@ -675,7 +675,8 @@ out:
}
static const char *ecryptfs_get_link(struct dentry *dentry,
- struct inode *inode, void **cookie)
+ struct inode *inode,
+ struct delayed_call *done)
{
size_t len;
char *buf;
@@ -689,7 +690,8 @@ static const char *ecryptfs_get_link(struct dentry *dentry,
fsstack_copy_attr_atime(d_inode(dentry),
d_inode(ecryptfs_dentry_to_lower(dentry)));
buf[len] = '\0';
- return *cookie = buf;
+ set_delayed_call(done, kfree_link, buf);
+ return buf;
}
/**
@@ -1102,7 +1104,6 @@ out:
const struct inode_operations ecryptfs_symlink_iops = {
.readlink = generic_readlink,
.get_link = ecryptfs_get_link,
- .put_link = kfree_put_link,
.permission = ecryptfs_permission,
.setattr = ecryptfs_setattr,
.getattr = ecryptfs_getattr_link,
diff --git a/fs/ext2/symlink.c b/fs/ext2/symlink.c
index 46905119a27c..3495d8ae4b33 100644
--- a/fs/ext2/symlink.c
+++ b/fs/ext2/symlink.c
@@ -23,7 +23,6 @@
const struct inode_operations ext2_symlink_inode_operations = {
.readlink = generic_readlink,
.get_link = page_get_link,
- .put_link = page_put_link,
.setattr = ext2_setattr,
#ifdef CONFIG_EXT2_FS_XATTR
.setxattr = generic_setxattr,
diff --git a/fs/ext4/symlink.c b/fs/ext4/symlink.c
index 3b4bfe2ebd75..2281ac27b213 100644
--- a/fs/ext4/symlink.c
+++ b/fs/ext4/symlink.c
@@ -24,7 +24,8 @@
#ifdef CONFIG_EXT4_FS_ENCRYPTION
static const char *ext4_encrypted_get_link(struct dentry *dentry,
- struct inode *inode, void **cookie)
+ struct inode *inode,
+ struct delayed_call *done)
{
struct page *cpage = NULL;
char *caddr, *paddr = NULL;
@@ -80,7 +81,8 @@ static const char *ext4_encrypted_get_link(struct dentry *dentry,
paddr[res] = '\0';
if (cpage)
page_cache_release(cpage);
- return *cookie = paddr;
+ set_delayed_call(done, kfree_link, paddr);
+ return paddr;
errout:
if (cpage)
page_cache_release(cpage);
@@ -91,7 +93,6 @@ errout:
const struct inode_operations ext4_encrypted_symlink_inode_operations = {
.readlink = generic_readlink,
.get_link = ext4_encrypted_get_link,
- .put_link = kfree_put_link,
.setattr = ext4_setattr,
.setxattr = generic_setxattr,
.getxattr = generic_getxattr,
@@ -103,7 +104,6 @@ const struct inode_operations ext4_encrypted_symlink_inode_operations = {
const struct inode_operations ext4_symlink_inode_operations = {
.readlink = generic_readlink,
.get_link = page_get_link,
- .put_link = page_put_link,
.setattr = ext4_setattr,
.setxattr = generic_setxattr,
.getxattr = generic_getxattr,
diff --git a/fs/f2fs/namei.c b/fs/f2fs/namei.c
index 2a8d84b727ce..e7587fce1b80 100644
--- a/fs/f2fs/namei.c
+++ b/fs/f2fs/namei.c
@@ -316,12 +316,14 @@ fail:
}
static const char *f2fs_get_link(struct dentry *dentry,
- struct inode *inode, void **cookie)
+ struct inode *inode,
+ struct delayed_call *done)
{
- const char *link = page_get_link(dentry, inode, cookie);
+ const char *link = page_get_link(dentry, inode, done);
if (!IS_ERR(link) && !*link) {
/* this is broken symlink case */
- page_put_link(NULL, *cookie);
+ do_delayed_call(done);
+ clear_delayed_call(done);
link = ERR_PTR(-ENOENT);
}
return link;
@@ -926,7 +928,8 @@ static int f2fs_rename2(struct inode *old_dir, struct dentry *old_dentry,
#ifdef CONFIG_F2FS_FS_ENCRYPTION
static const char *f2fs_encrypted_get_link(struct dentry *dentry,
- struct inode *inode, void **cookie)
+ struct inode *inode,
+ struct delayed_call *done)
{
struct page *cpage = NULL;
char *caddr, *paddr = NULL;
@@ -988,7 +991,8 @@ static const char *f2fs_encrypted_get_link(struct dentry *dentry,
paddr[res] = '\0';
page_cache_release(cpage);
- return *cookie = paddr;
+ set_delayed_call(done, kfree_link, paddr);
+ return paddr;
errout:
kfree(cstr.name);
f2fs_fname_crypto_free_buffer(&pstr);
@@ -999,7 +1003,6 @@ errout:
const struct inode_operations f2fs_encrypted_symlink_inode_operations = {
.readlink = generic_readlink,
.get_link = f2fs_encrypted_get_link,
- .put_link = kfree_put_link,
.getattr = f2fs_getattr,
.setattr = f2fs_setattr,
.setxattr = generic_setxattr,
@@ -1035,7 +1038,6 @@ const struct inode_operations f2fs_dir_inode_operations = {
const struct inode_operations f2fs_symlink_inode_operations = {
.readlink = generic_readlink,
.get_link = f2fs_get_link,
- .put_link = page_put_link,
.getattr = f2fs_getattr,
.setattr = f2fs_setattr,
#ifdef CONFIG_F2FS_FS_XATTR
diff --git a/fs/fuse/dir.c b/fs/fuse/dir.c
index def0a4d082bc..712601f299b8 100644
--- a/fs/fuse/dir.c
+++ b/fs/fuse/dir.c
@@ -1366,7 +1366,8 @@ static int fuse_readdir(struct file *file, struct dir_context *ctx)
}
static const char *fuse_get_link(struct dentry *dentry,
- struct inode *inode, void **cookie)
+ struct inode *inode,
+ struct delayed_call *done)
{
struct fuse_conn *fc = get_fuse_conn(inode);
FUSE_ARGS(args);
@@ -1392,7 +1393,7 @@ static const char *fuse_get_link(struct dentry *dentry,
link = ERR_PTR(ret);
} else {
link[ret] = '\0';
- *cookie = link;
+ set_delayed_call(done, kfree_link, link);
}
fuse_invalidate_atime(inode);
return link;
@@ -1913,7 +1914,6 @@ static const struct inode_operations fuse_common_inode_operations = {
static const struct inode_operations fuse_symlink_inode_operations = {
.setattr = fuse_setattr,
.get_link = fuse_get_link,
- .put_link = kfree_put_link,
.readlink = generic_readlink,
.getattr = fuse_getattr,
.setxattr = fuse_setxattr,
diff --git a/fs/gfs2/inode.c b/fs/gfs2/inode.c
index 1095056046cc..1bae189f3245 100644
--- a/fs/gfs2/inode.c
+++ b/fs/gfs2/inode.c
@@ -1715,7 +1715,7 @@ static int gfs2_rename2(struct inode *odir, struct dentry *odentry,
* gfs2_get_link - Follow a symbolic link
* @dentry: The dentry of the link
* @inode: The inode of the link
- * @cookie: place to store the information for ->put_link()
+ * @done: destructor for return value
*
* This can handle symlinks of any size.
*
@@ -1723,7 +1723,8 @@ static int gfs2_rename2(struct inode *odir, struct dentry *odentry,
*/
static const char *gfs2_get_link(struct dentry *dentry,
- struct inode *inode, void **cookie)
+ struct inode *inode,
+ struct delayed_call *done)
{
struct gfs2_inode *ip = GFS2_I(inode);
struct gfs2_holder i_gh;
@@ -1764,7 +1765,7 @@ static const char *gfs2_get_link(struct dentry *dentry,
out:
gfs2_glock_dq_uninit(&i_gh);
if (!IS_ERR(buf))
- *cookie = buf;
+ set_delayed_call(done, kfree_link, buf);
return buf;
}
@@ -2138,7 +2139,6 @@ const struct inode_operations gfs2_dir_iops = {
const struct inode_operations gfs2_symlink_iops = {
.readlink = generic_readlink,
.get_link = gfs2_get_link,
- .put_link = kfree_put_link,
.permission = gfs2_permission,
.setattr = gfs2_setattr,
.getattr = gfs2_getattr,
diff --git a/fs/hostfs/hostfs_kern.c b/fs/hostfs/hostfs_kern.c
index 6ce5309ecb7b..7db524cc85b6 100644
--- a/fs/hostfs/hostfs_kern.c
+++ b/fs/hostfs/hostfs_kern.c
@@ -893,12 +893,13 @@ static const struct inode_operations hostfs_dir_iops = {
};
static const char *hostfs_get_link(struct dentry *dentry,
- struct inode *inode, void **cookie)
+ struct inode *inode,
+ struct delayed_call *done)
{
char *link;
if (!dentry)
return ERR_PTR(-ECHILD);
- link = __getname();
+ link = kmalloc(PATH_MAX, GFP_KERNEL);
if (link) {
char *path = dentry_name(dentry);
int err = -ENOMEM;
@@ -909,25 +910,20 @@ static const char *hostfs_get_link(struct dentry *dentry,
__putname(path);
}
if (err < 0) {
- __putname(link);
+ kfree(link);
return ERR_PTR(err);
}
} else {
return ERR_PTR(-ENOMEM);
}
- return *cookie = link;
-}
-
-static void hostfs_put_link(struct inode *unused, void *cookie)
-{
- __putname(cookie);
+ set_delayed_call(done, kfree_link, link);
+ return link;
}
static const struct inode_operations hostfs_link_iops = {
.readlink = generic_readlink,
.get_link = hostfs_get_link,
- .put_link = hostfs_put_link,
};
static int hostfs_fill_sb_common(struct super_block *sb, void *d, int silent)
diff --git a/fs/jfs/symlink.c b/fs/jfs/symlink.c
index 02113282772e..f8db4fde0b0b 100644
--- a/fs/jfs/symlink.c
+++ b/fs/jfs/symlink.c
@@ -34,7 +34,6 @@ const struct inode_operations jfs_fast_symlink_inode_operations = {
const struct inode_operations jfs_symlink_inode_operations = {
.readlink = generic_readlink,
.get_link = page_get_link,
- .put_link = page_put_link,
.setattr = jfs_setattr,
.setxattr = jfs_setxattr,
.getxattr = jfs_getxattr,
diff --git a/fs/kernfs/symlink.c b/fs/kernfs/symlink.c
index f9efdaeda7b0..117b8b3416f9 100644
--- a/fs/kernfs/symlink.c
+++ b/fs/kernfs/symlink.c
@@ -113,22 +113,24 @@ static int kernfs_getlink(struct dentry *dentry, char *path)
}
static const char *kernfs_iop_get_link(struct dentry *dentry,
- struct inode *inode, void **cookie)
+ struct inode *inode,
+ struct delayed_call *done)
{
- int error = -ENOMEM;
- char *page;
+ char *body;
+ int error;
if (!dentry)
return ERR_PTR(-ECHILD);
- page = kzalloc(PAGE_SIZE, GFP_KERNEL);
- if (!page)
+ body = kzalloc(PAGE_SIZE, GFP_KERNEL);
+ if (!body)
return ERR_PTR(-ENOMEM);
- error = kernfs_getlink(dentry, page);
+ error = kernfs_getlink(dentry, body);
if (unlikely(error < 0)) {
- kfree(page);
+ kfree(body);
return ERR_PTR(error);
}
- return *cookie = page;
+ set_delayed_call(done, kfree_link, body);
+ return body;
}
const struct inode_operations kernfs_symlink_iops = {
@@ -138,7 +140,6 @@ const struct inode_operations kernfs_symlink_iops = {
.listxattr = kernfs_iop_listxattr,
.readlink = generic_readlink,
.get_link = kernfs_iop_get_link,
- .put_link = kfree_put_link,
.setattr = kernfs_iop_setattr,
.getattr = kernfs_iop_getattr,
.permission = kernfs_iop_permission,
diff --git a/fs/libfs.c b/fs/libfs.c
index fec7ab0632dc..01491299f348 100644
--- a/fs/libfs.c
+++ b/fs/libfs.c
@@ -1019,11 +1019,12 @@ int noop_fsync(struct file *file, loff_t start, loff_t end, int datasync)
}
EXPORT_SYMBOL(noop_fsync);
-void kfree_put_link(struct inode *unused, void *cookie)
+/* Because kfree isn't assignment-compatible with void(void*) ;-/ */
+void kfree_link(void *p)
{
- kfree(cookie);
+ kfree(p);
}
-EXPORT_SYMBOL(kfree_put_link);
+EXPORT_SYMBOL(kfree_link);
/*
* nop .set_page_dirty method so that people can use .page_mkwrite on
@@ -1087,7 +1088,7 @@ simple_nosetlease(struct file *filp, long arg, struct file_lock **flp,
EXPORT_SYMBOL(simple_nosetlease);
const char *simple_get_link(struct dentry *dentry, struct inode *inode,
- void **cookie)
+ struct delayed_call *done)
{
return inode->i_link;
}
diff --git a/fs/minix/inode.c b/fs/minix/inode.c
index 3cce709a8729..cb1789ca1ee6 100644
--- a/fs/minix/inode.c
+++ b/fs/minix/inode.c
@@ -436,7 +436,6 @@ static const struct address_space_operations minix_aops = {
static const struct inode_operations minix_symlink_inode_operations = {
.readlink = generic_readlink,
.get_link = page_get_link,
- .put_link = page_put_link,
.getattr = minix_getattr,
};
diff --git a/fs/namei.c b/fs/namei.c
index 8f517888c3e1..3c909aebef70 100644
--- a/fs/namei.c
+++ b/fs/namei.c
@@ -505,13 +505,13 @@ struct nameidata {
int total_link_count;
struct saved {
struct path link;
- void *cookie;
+ struct delayed_call done;
const char *name;
- struct inode *inode;
unsigned seq;
} *stack, internal[EMBEDDED_LEVELS];
struct filename *name;
struct nameidata *saved;
+ struct inode *link_inode;
unsigned root_seq;
int dfd;
};
@@ -592,11 +592,8 @@ static void drop_links(struct nameidata *nd)
int i = nd->depth;
while (i--) {
struct saved *last = nd->stack + i;
- struct inode *inode = last->inode;
- if (last->cookie && inode->i_op->put_link) {
- inode->i_op->put_link(inode, last->cookie);
- last->cookie = NULL;
- }
+ do_delayed_call(&last->done);
+ clear_delayed_call(&last->done);
}
}
@@ -858,9 +855,7 @@ void nd_jump_link(struct path *path)
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(inode, last->cookie);
+ do_delayed_call(&last->done);
if (!(nd->flags & LOOKUP_RCU))
path_put(&last->link);
}
@@ -892,7 +887,7 @@ static inline int may_follow_link(struct nameidata *nd)
return 0;
/* Allowed if owner and follower match. */
- inode = nd->stack[0].inode;
+ inode = nd->link_inode;
if (uid_eq(current_cred()->fsuid, inode->i_uid))
return 0;
@@ -983,7 +978,7 @@ const char *get_link(struct nameidata *nd)
{
struct saved *last = nd->stack + nd->depth - 1;
struct dentry *dentry = last->link.dentry;
- struct inode *inode = last->inode;
+ struct inode *inode = nd->link_inode;
int error;
const char *res;
@@ -1004,23 +999,21 @@ const char *get_link(struct nameidata *nd)
nd->last_type = LAST_BIND;
res = inode->i_link;
if (!res) {
+ const char * (*get)(struct dentry *, struct inode *,
+ struct delayed_call *);
+ get = inode->i_op->get_link;
if (nd->flags & LOOKUP_RCU) {
- res = inode->i_op->get_link(NULL, inode,
- &last->cookie);
+ res = get(NULL, inode, &last->done);
if (res == ERR_PTR(-ECHILD)) {
if (unlikely(unlazy_walk(nd, NULL, 0)))
return ERR_PTR(-ECHILD);
- res = inode->i_op->get_link(dentry, inode,
- &last->cookie);
+ res = get(dentry, inode, &last->done);
}
} else {
- res = inode->i_op->get_link(dentry, inode,
- &last->cookie);
+ res = get(dentry, inode, &last->done);
}
- if (IS_ERR_OR_NULL(res)) {
- last->cookie = NULL;
+ if (IS_ERR_OR_NULL(res))
return res;
- }
}
if (*res == '/') {
if (nd->flags & LOOKUP_RCU) {
@@ -1699,8 +1692,8 @@ static int pick_link(struct nameidata *nd, struct path *link,
last = nd->stack + nd->depth++;
last->link = *link;
- last->cookie = NULL;
- last->inode = inode;
+ clear_delayed_call(&last->done);
+ nd->link_inode = inode;
last->seq = seq;
return 1;
}
@@ -4508,26 +4501,25 @@ EXPORT_SYMBOL(readlink_copy);
*/
int generic_readlink(struct dentry *dentry, char __user *buffer, int buflen)
{
- void *cookie;
+ DEFINE_DELAYED_CALL(done);
struct inode *inode = d_inode(dentry);
const char *link = inode->i_link;
int res;
if (!link) {
- link = inode->i_op->get_link(dentry, inode, &cookie);
+ link = inode->i_op->get_link(dentry, inode, &done);
if (IS_ERR(link))
return PTR_ERR(link);
}
res = readlink_copy(buffer, buflen, link);
- if (inode->i_op->put_link)
- inode->i_op->put_link(inode, cookie);
+ do_delayed_call(&done);
return res;
}
EXPORT_SYMBOL(generic_readlink);
/* get the link contents into pagecache */
const char *page_get_link(struct dentry *dentry, struct inode *inode,
- void **cookie)
+ struct delayed_call *callback)
{
char *kaddr;
struct page *page;
@@ -4546,7 +4538,7 @@ const char *page_get_link(struct dentry *dentry, struct inode *inode,
if (IS_ERR(page))
return (char*)page;
}
- *cookie = page;
+ set_delayed_call(callback, page_put_link, page);
BUG_ON(mapping_gfp_mask(mapping) & __GFP_HIGHMEM);
kaddr = page_address(page);
nd_terminate_link(kaddr, inode->i_size, PAGE_SIZE - 1);
@@ -4555,21 +4547,19 @@ const char *page_get_link(struct dentry *dentry, struct inode *inode,
EXPORT_SYMBOL(page_get_link);
-void page_put_link(struct inode *unused, void *cookie)
+void page_put_link(void *arg)
{
- struct page *page = cookie;
- page_cache_release(page);
+ put_page(arg);
}
EXPORT_SYMBOL(page_put_link);
int page_readlink(struct dentry *dentry, char __user *buffer, int buflen)
{
- void *cookie = NULL;
+ DEFINE_DELAYED_CALL(done);
int res = readlink_copy(buffer, buflen,
page_get_link(dentry, d_inode(dentry),
- &cookie));
- if (cookie)
- page_put_link(NULL, cookie);
+ &done));
+ do_delayed_call(&done);
return res;
}
EXPORT_SYMBOL(page_readlink);
@@ -4619,6 +4609,5 @@ EXPORT_SYMBOL(page_symlink);
const struct inode_operations page_symlink_inode_operations = {
.readlink = generic_readlink,
.get_link = page_get_link,
- .put_link = page_put_link,
};
EXPORT_SYMBOL(page_symlink_inode_operations);
diff --git a/fs/ncpfs/inode.c b/fs/ncpfs/inode.c
index 3ab6cdbcde60..ce1eb3f9dfe8 100644
--- a/fs/ncpfs/inode.c
+++ b/fs/ncpfs/inode.c
@@ -245,7 +245,6 @@ static void ncp_set_attr(struct inode *inode, struct ncp_entry_info *nwinfo)
static const struct inode_operations ncp_symlink_inode_operations = {
.readlink = generic_readlink,
.get_link = page_get_link,
- .put_link = page_put_link,
.setattr = ncp_notify_change,
};
#endif
diff --git a/fs/nfs/symlink.c b/fs/nfs/symlink.c
index 95c69af7e4d0..4fe3eead3868 100644
--- a/fs/nfs/symlink.c
+++ b/fs/nfs/symlink.c
@@ -43,7 +43,8 @@ error:
}
static const char *nfs_get_link(struct dentry *dentry,
- struct inode *inode, void **cookie)
+ struct inode *inode,
+ struct delayed_call *done)
{
struct page *page;
void *err;
@@ -68,7 +69,7 @@ static const char *nfs_get_link(struct dentry *dentry,
if (IS_ERR(page))
return ERR_CAST(page);
}
- *cookie = page;
+ set_delayed_call(done, page_put_link, page);
return page_address(page);
}
@@ -78,7 +79,6 @@ static const char *nfs_get_link(struct dentry *dentry,
const struct inode_operations nfs_symlink_inode_operations = {
.readlink = generic_readlink,
.get_link = nfs_get_link,
- .put_link = page_put_link,
.getattr = nfs_getattr,
.setattr = nfs_setattr,
};
diff --git a/fs/nilfs2/namei.c b/fs/nilfs2/namei.c
index 63dddb7d4b18..7ccdb961eea9 100644
--- a/fs/nilfs2/namei.c
+++ b/fs/nilfs2/namei.c
@@ -570,7 +570,6 @@ const struct inode_operations nilfs_special_inode_operations = {
const struct inode_operations nilfs_symlink_inode_operations = {
.readlink = generic_readlink,
.get_link = page_get_link,
- .put_link = page_put_link,
.permission = nilfs_permission,
};
diff --git a/fs/ocfs2/symlink.c b/fs/ocfs2/symlink.c
index b4e79bc720f7..6c2a3e3c521c 100644
--- a/fs/ocfs2/symlink.c
+++ b/fs/ocfs2/symlink.c
@@ -89,7 +89,6 @@ const struct address_space_operations ocfs2_fast_symlink_aops = {
const struct inode_operations ocfs2_symlink_inode_operations = {
.readlink = generic_readlink,
.get_link = page_get_link,
- .put_link = page_put_link,
.getattr = ocfs2_getattr,
.setattr = ocfs2_setattr,
.setxattr = generic_setxattr,
diff --git a/fs/overlayfs/inode.c b/fs/overlayfs/inode.c
index 38a0b8b9f8b9..964a60fa7afc 100644
--- a/fs/overlayfs/inode.c
+++ b/fs/overlayfs/inode.c
@@ -131,19 +131,12 @@ out_dput:
return err;
}
-
-struct ovl_link_data {
- struct dentry *realdentry;
- void *cookie;
-};
-
static const char *ovl_get_link(struct dentry *dentry,
- struct inode *inode, void **cookie)
+ struct inode *inode,
+ struct delayed_call *done)
{
struct dentry *realdentry;
struct inode *realinode;
- struct ovl_link_data *data = NULL;
- const char *ret;
if (!dentry)
return ERR_PTR(-ECHILD);
@@ -154,38 +147,7 @@ static const char *ovl_get_link(struct dentry *dentry,
if (WARN_ON(!realinode->i_op->get_link))
return ERR_PTR(-EPERM);
- if (realinode->i_op->put_link) {
- data = kmalloc(sizeof(struct ovl_link_data), GFP_KERNEL);
- if (!data)
- return ERR_PTR(-ENOMEM);
- data->realdentry = realdentry;
- }
-
- ret = realinode->i_op->get_link(realdentry, realinode, 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 inode *unused, void *c)
-{
- struct inode *realinode;
- struct ovl_link_data *data = c;
-
- if (!data)
- return;
-
- realinode = data->realdentry->d_inode;
- realinode->i_op->put_link(realinode, data->cookie);
- kfree(data);
+ return realinode->i_op->get_link(realdentry, realinode, done);
}
static int ovl_readlink(struct dentry *dentry, char __user *buf, int bufsiz)
@@ -383,7 +345,6 @@ static const struct inode_operations ovl_file_inode_operations = {
static const struct inode_operations ovl_symlink_inode_operations = {
.setattr = ovl_setattr,
.get_link = ovl_get_link,
- .put_link = ovl_put_link,
.readlink = ovl_readlink,
.getattr = ovl_getattr,
.setxattr = ovl_setxattr,
diff --git a/fs/proc/base.c b/fs/proc/base.c
index 1a489e2b9768..71660bb9e9f7 100644
--- a/fs/proc/base.c
+++ b/fs/proc/base.c
@@ -1565,7 +1565,8 @@ static int proc_exe_link(struct dentry *dentry, struct path *exe_path)
}
static const char *proc_pid_get_link(struct dentry *dentry,
- struct inode *inode, void **cookie)
+ struct inode *inode,
+ struct delayed_call *done)
{
struct path path;
int error = -EACCES;
@@ -1949,12 +1950,13 @@ struct map_files_info {
*/
static const char *
proc_map_files_get_link(struct dentry *dentry,
- struct inode *inode, void **cookie)
+ struct inode *inode,
+ struct delayed_call *done)
{
if (!capable(CAP_SYS_ADMIN))
return ERR_PTR(-EPERM);
- return proc_pid_get_link(dentry, inode, NULL);
+ return proc_pid_get_link(dentry, inode, done);
}
/*
diff --git a/fs/proc/inode.c b/fs/proc/inode.c
index 10360b268794..d0e9b9b6223e 100644
--- a/fs/proc/inode.c
+++ b/fs/proc/inode.c
@@ -393,25 +393,25 @@ static const struct file_operations proc_reg_file_ops_no_compat = {
};
#endif
+static void proc_put_link(void *p)
+{
+ unuse_pde(p);
+}
+
static const char *proc_get_link(struct dentry *dentry,
- struct inode *inode, void **cookie)
+ struct inode *inode,
+ struct delayed_call *done)
{
struct proc_dir_entry *pde = PDE(inode);
if (unlikely(!use_pde(pde)))
return ERR_PTR(-EINVAL);
- *cookie = pde;
+ set_delayed_call(done, proc_put_link, pde);
return pde->data;
}
-static void proc_put_link(struct inode *unused, void *p)
-{
- unuse_pde(p);
-}
-
const struct inode_operations proc_link_inode_operations = {
.readlink = generic_readlink,
.get_link = proc_get_link,
- .put_link = proc_put_link,
};
struct inode *proc_get_inode(struct super_block *sb, struct proc_dir_entry *de)
diff --git a/fs/proc/namespaces.c b/fs/proc/namespaces.c
index 63861c15e109..1dece8781f91 100644
--- a/fs/proc/namespaces.c
+++ b/fs/proc/namespaces.c
@@ -31,7 +31,8 @@ static const struct proc_ns_operations *ns_entries[] = {
};
static const char *proc_ns_get_link(struct dentry *dentry,
- struct inode *inode, void **cookie)
+ struct inode *inode,
+ struct delayed_call *done)
{
const struct proc_ns_operations *ns_ops = PROC_I(inode)->ns_ops;
struct task_struct *task;
diff --git a/fs/proc/self.c b/fs/proc/self.c
index 7a8b19ead3b6..67e8db442cf0 100644
--- a/fs/proc/self.c
+++ b/fs/proc/self.c
@@ -19,7 +19,8 @@ static int proc_self_readlink(struct dentry *dentry, char __user *buffer,
}
static const char *proc_self_get_link(struct dentry *dentry,
- struct inode *inode, void **cookie)
+ struct inode *inode,
+ struct delayed_call *done)
{
struct pid_namespace *ns = inode->i_sb->s_fs_info;
pid_t tgid = task_tgid_nr_ns(current, ns);
@@ -32,13 +33,13 @@ static const char *proc_self_get_link(struct dentry *dentry,
if (unlikely(!name))
return dentry ? ERR_PTR(-ENOMEM) : ERR_PTR(-ECHILD);
sprintf(name, "%d", tgid);
- return *cookie = name;
+ set_delayed_call(done, kfree_link, name);
+ return name;
}
static const struct inode_operations proc_self_inode_operations = {
.readlink = proc_self_readlink,
.get_link = proc_self_get_link,
- .put_link = kfree_put_link,
};
static unsigned self_inum;
diff --git a/fs/proc/thread_self.c b/fs/proc/thread_self.c
index 03eaa84604da..9eacd59e0360 100644
--- a/fs/proc/thread_self.c
+++ b/fs/proc/thread_self.c
@@ -20,7 +20,8 @@ static int proc_thread_self_readlink(struct dentry *dentry, char __user *buffer,
}
static const char *proc_thread_self_get_link(struct dentry *dentry,
- struct inode *inode, void **cookie)
+ struct inode *inode,
+ struct delayed_call *done)
{
struct pid_namespace *ns = inode->i_sb->s_fs_info;
pid_t tgid = task_tgid_nr_ns(current, ns);
@@ -34,13 +35,13 @@ static const char *proc_thread_self_get_link(struct dentry *dentry,
if (unlikely(!name))
return dentry ? ERR_PTR(-ENOMEM) : ERR_PTR(-ECHILD);
sprintf(name, "%d/task/%d", tgid, pid);
- return *cookie = name;
+ set_delayed_call(done, kfree_link, name);
+ return name;
}
static const struct inode_operations proc_thread_self_inode_operations = {
.readlink = proc_thread_self_readlink,
.get_link = proc_thread_self_get_link,
- .put_link = kfree_put_link,
};
static unsigned thread_self_inum;
diff --git a/fs/reiserfs/namei.c b/fs/reiserfs/namei.c
index ecbf11e961ab..2a12d46d7fb4 100644
--- a/fs/reiserfs/namei.c
+++ b/fs/reiserfs/namei.c
@@ -1666,7 +1666,6 @@ const struct inode_operations reiserfs_dir_inode_operations = {
const struct inode_operations reiserfs_symlink_inode_operations = {
.readlink = generic_readlink,
.get_link = page_get_link,
- .put_link = page_put_link,
.setattr = reiserfs_setattr,
.setxattr = reiserfs_setxattr,
.getxattr = reiserfs_getxattr,
diff --git a/fs/squashfs/symlink.c b/fs/squashfs/symlink.c
index 7c635a5da783..dbcc2f54bad4 100644
--- a/fs/squashfs/symlink.c
+++ b/fs/squashfs/symlink.c
@@ -120,7 +120,6 @@ const struct address_space_operations squashfs_symlink_aops = {
const struct inode_operations squashfs_symlink_inode_ops = {
.readlink = generic_readlink,
.get_link = page_get_link,
- .put_link = page_put_link,
.getxattr = generic_getxattr,
.listxattr = squashfs_listxattr
};
diff --git a/fs/sysv/inode.c b/fs/sysv/inode.c
index 80a40bcb721c..07ac18c355e7 100644
--- a/fs/sysv/inode.c
+++ b/fs/sysv/inode.c
@@ -147,7 +147,6 @@ static inline void write3byte(struct sysv_sb_info *sbi,
static const struct inode_operations sysv_symlink_inode_operations = {
.readlink = generic_readlink,
.get_link = page_get_link,
- .put_link = page_put_link,
.getattr = sysv_getattr,
};
diff --git a/fs/xfs/xfs_iops.c b/fs/xfs/xfs_iops.c
index f638fd58b5b3..06eafafe636e 100644
--- a/fs/xfs/xfs_iops.c
+++ b/fs/xfs/xfs_iops.c
@@ -417,7 +417,7 @@ STATIC const char *
xfs_vn_get_link(
struct dentry *dentry,
struct inode *inode,
- void **cookie)
+ struct delayed_call *done)
{
char *link;
int error = -ENOMEM;
@@ -433,7 +433,8 @@ xfs_vn_get_link(
if (unlikely(error))
goto out_kfree;
- return *cookie = link;
+ set_delayed_call(done, kfree_link, link);
+ return link;
out_kfree:
kfree(link);
@@ -1177,7 +1178,6 @@ static const struct inode_operations xfs_dir_ci_inode_operations = {
static const struct inode_operations xfs_symlink_inode_operations = {
.readlink = generic_readlink,
.get_link = xfs_vn_get_link,
- .put_link = kfree_put_link,
.getattr = xfs_vn_getattr,
.setattr = xfs_vn_setattr,
.setxattr = generic_setxattr,