Commit fceef393 authored by Al Viro's avatar Al Viro

switch ->get_link() to delayed_call, kill ->put_link()

Signed-off-by: default avatarAl Viro <viro@zeniv.linux.org.uk>
parent cd3417c8
......@@ -51,7 +51,6 @@ prototypes:
struct inode *, struct dentry *, unsigned int);
int (*readlink) (struct dentry *, char __user *,int);
const char *(*get_link) (struct dentry *, struct inode *, void **);
void (*put_link) (struct inode *, void *);
void (*truncate) (struct inode *);
int (*permission) (struct inode *, int, unsigned int);
int (*get_acl)(struct inode *, int);
......@@ -84,7 +83,6 @@ rename: yes (all) (see below)
rename2: yes (all) (see below)
readlink: no
get_link: no
put_link: no
setattr: yes
permission: no (may not block if called in rcu-walk mode)
get_acl: no
......
......@@ -515,3 +515,9 @@ in your dentry operations instead.
* ->get_link() gets inode as a separate argument
* ->get_link() may be called in RCU mode - in that case NULL
dentry is passed
--
[mandatory]
->get_link() gets struct delayed_call *done now, and should do
set_delayed_call() where it used to set *cookie.
->put_link() is gone - just give the destructor to set_delayed_call()
in ->get_link().
......@@ -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);
const char *(*follow_link) (struct dentry *, void **);
void (*put_link) (struct inode *, void *);
const char *(*get_link) (struct dentry *, struct inode *,
struct delayed_call *);
int (*permission) (struct inode *, int);
int (*get_acl)(struct inode *, int);
int (*setattr) (struct dentry *, struct iattr *);
......@@ -434,20 +434,19 @@ otherwise noted.
readlink: called by the readlink(2) system call. Only required if
you want to support reading symbolic links
follow_link: called by the VFS to follow a symbolic link to the
get_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 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 stored by follow_link() is passed
to this method as the last parameter; only called when
cookie isn't NULL.
pinned, arrange for its release by having get_link(..., ..., done)
do set_delayed_call(done, destructor, argument).
In that case destructor(argument) will be called once VFS is
done with the body you've returned.
May be called in RCU mode; that is indicated by NULL dentry
argument. If request can't be handled without leaving RCU mode,
have it return ERR_PTR(-ECHILD).
permission: called by the VFS to check for access rights on a POSIX-like
filesystem.
......
......@@ -118,8 +118,14 @@ static int ll_readlink_internal(struct inode *inode,
return rc;
}
static void ll_put_link(void *p)
{
ptlrpc_req_finished(p);
}
static const char *ll_get_link(struct dentry *dentry,
struct inode *inode, void **cookie)
struct inode *inode,
struct delayed_call *done)
{
struct ptlrpc_request *request = NULL;
int rc;
......@@ -137,22 +143,16 @@ static const char *ll_get_link(struct dentry *dentry,
}
/* symname may contain a pointer to the request message buffer,
* we delay request releasing until ll_put_link then.
* we delay request releasing then.
*/
*cookie = request;
set_delayed_call(done, ll_put_link, request);
return symname;
}
static void ll_put_link(struct inode *unused, void *cookie)
{
ptlrpc_req_finished(cookie);
}
struct inode_operations ll_fast_symlink_inode_operations = {
.readlink = generic_readlink,
.setattr = ll_setattr,
.get_link = ll_get_link,
.put_link = ll_put_link,
.getattr = ll_getattr,
.permission = ll_inode_permission,
.setxattr = ll_setxattr,
......
......@@ -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,
};
......
......@@ -902,12 +902,13 @@ v9fs_vfs_mknod_dotl(struct inode *dir, struct dentry *dentry, umode_t omode,
* 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,
......
......@@ -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,
};
......@@ -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;
......
......@@ -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,
......
......@@ -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,
......
......@@ -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 *);
......
......@@ -627,7 +627,8 @@ cifs_hardlink(struct dentry *old_file, struct inode *inode,
}
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
......
......@@ -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,
};
......
......@@ -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,
};
......@@ -675,7 +675,8 @@ static char *ecryptfs_readlink_lower(struct dentry *dentry, size_t *bufsiz)
}
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 @@ static int ecryptfs_removexattr(struct dentry *dentry, const char *name)
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,
......
......@@ -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,
......
......@@ -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 @@ static const char *ext4_encrypted_get_link(struct dentry *dentry,
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,
......
......@@ -316,12 +316,14 @@ static int f2fs_unlink(struct inode *dir, struct dentry *dentry)
}
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 @@ static const char *f2fs_encrypted_get_link(struct dentry *dentry,
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
......
......@@ -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,
......
......@@ -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,
......
......@@ -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)
......
......@@ -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,
......
......@@ -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,
......
......@@ -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;
}
......
......@@ -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,
};
......
......@@ -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