switch ->get_link() to delayed_call, kill ->put_link()
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
This commit is contained in:
parent
cd3417c8fc
commit
fceef393a5
43 changed files with 206 additions and 218 deletions
|
@ -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 @@ failed:
|
|||
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 @@ 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,
|
||||
|
|
|
@ -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_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
|
||||
|
|
|
@ -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 @@ 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,
|
||||
|
|
|
@ -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 @@ 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,
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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,
|
||||
};
|
||||
|
||||
|
|
63
fs/namei.c
63
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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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,
|
||||
};
|
||||
|
|
|
@ -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,
|
||||
};
|
||||
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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
|
||||
};
|
||||
|
|
|
@ -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,
|
||||
};
|
||||
|
||||
|
|
|
@ -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,
|
||||
|
|
34
include/linux/delayed_call.h
Normal file
34
include/linux/delayed_call.h
Normal file
|
@ -0,0 +1,34 @@
|
|||
#ifndef _DELAYED_CALL_H
|
||||
#define _DELAYED_CALL_H
|
||||
|
||||
/*
|
||||
* Poor man's closures; I wish we could've done them sanely polymorphic,
|
||||
* but...
|
||||
*/
|
||||
|
||||
struct delayed_call {
|
||||
void (*fn)(void *);
|
||||
void *arg;
|
||||
};
|
||||
|
||||
#define DEFINE_DELAYED_CALL(name) struct delayed_call name = {NULL, NULL}
|
||||
|
||||
/* I really wish we had closures with sane typechecking... */
|
||||
static inline void set_delayed_call(struct delayed_call *call,
|
||||
void (*fn)(void *), void *arg)
|
||||
{
|
||||
call->fn = fn;
|
||||
call->arg = arg;
|
||||
}
|
||||
|
||||
static inline void do_delayed_call(struct delayed_call *call)
|
||||
{
|
||||
if (call->fn)
|
||||
call->fn(call->arg);
|
||||
}
|
||||
|
||||
static inline void clear_delayed_call(struct delayed_call *call)
|
||||
{
|
||||
call->fn = NULL;
|
||||
}
|
||||
#endif
|
|
@ -31,6 +31,7 @@
|
|||
#include <linux/blk_types.h>
|
||||
#include <linux/workqueue.h>
|
||||
#include <linux/percpu-rwsem.h>
|
||||
#include <linux/delayed_call.h>
|
||||
|
||||
#include <asm/byteorder.h>
|
||||
#include <uapi/linux/fs.h>
|
||||
|
@ -1633,12 +1634,11 @@ struct file_operations {
|
|||
|
||||
struct inode_operations {
|
||||
struct dentry * (*lookup) (struct inode *,struct dentry *, unsigned int);
|
||||
const char * (*get_link) (struct dentry *, struct inode *, void **);
|
||||
const char * (*get_link) (struct dentry *, struct inode *, struct delayed_call *);
|
||||
int (*permission) (struct inode *, int);
|
||||
struct posix_acl * (*get_acl)(struct inode *, int);
|
||||
|
||||
int (*readlink) (struct dentry *, char __user *,int);
|
||||
void (*put_link) (struct inode *, void *);
|
||||
|
||||
int (*create) (struct inode *,struct dentry *, umode_t, bool);
|
||||
int (*link) (struct dentry *,struct inode *,struct dentry *);
|
||||
|
@ -2736,13 +2736,14 @@ extern const struct file_operations generic_ro_fops;
|
|||
|
||||
extern int readlink_copy(char __user *, int, const char *);
|
||||
extern int page_readlink(struct dentry *, char __user *, int);
|
||||
extern const char *page_get_link(struct dentry *, struct inode *, void **);
|
||||
extern void page_put_link(struct inode *, void *);
|
||||
extern const char *page_get_link(struct dentry *, struct inode *,
|
||||
struct delayed_call *);
|
||||
extern void page_put_link(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 inode *, void *);
|
||||
extern void kfree_link(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);
|
||||
|
@ -2753,7 +2754,8 @@ void __inode_sub_bytes(struct inode *inode, loff_t bytes);
|
|||
void inode_sub_bytes(struct inode *inode, loff_t bytes);
|
||||
loff_t inode_get_bytes(struct inode *inode);
|
||||
void inode_set_bytes(struct inode *inode, loff_t bytes);
|
||||
const char *simple_get_link(struct dentry *, struct inode *, void **);
|
||||
const char *simple_get_link(struct dentry *, struct inode *,
|
||||
struct delayed_call *);
|
||||
extern const struct inode_operations simple_symlink_inode_operations;
|
||||
|
||||
extern int iterate_dir(struct file *, struct dir_context *);
|
||||
|
|
19
mm/shmem.c
19
mm/shmem.c
|
@ -2496,8 +2496,15 @@ static int shmem_symlink(struct inode *dir, struct dentry *dentry, const char *s
|
|||
return 0;
|
||||
}
|
||||
|
||||
static void shmem_put_link(void *arg)
|
||||
{
|
||||
mark_page_accessed(arg);
|
||||
put_page(arg);
|
||||
}
|
||||
|
||||
static const char *shmem_get_link(struct dentry *dentry,
|
||||
struct inode *inode, void **cookie)
|
||||
struct inode *inode,
|
||||
struct delayed_call *done)
|
||||
{
|
||||
struct page *page = NULL;
|
||||
int error;
|
||||
|
@ -2515,17 +2522,10 @@ static const char *shmem_get_link(struct dentry *dentry,
|
|||
return ERR_PTR(error);
|
||||
unlock_page(page);
|
||||
}
|
||||
*cookie = page;
|
||||
set_delayed_call(done, shmem_put_link, page);
|
||||
return page_address(page);
|
||||
}
|
||||
|
||||
static void shmem_put_link(struct inode *unused, void *cookie)
|
||||
{
|
||||
struct page *page = cookie;
|
||||
mark_page_accessed(page);
|
||||
page_cache_release(page);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_TMPFS_XATTR
|
||||
/*
|
||||
* Superblocks without xattr inode operations may get some security.* xattr
|
||||
|
@ -2680,7 +2680,6 @@ static const struct inode_operations shmem_short_symlink_operations = {
|
|||
static const struct inode_operations shmem_symlink_inode_operations = {
|
||||
.readlink = generic_readlink,
|
||||
.get_link = shmem_get_link,
|
||||
.put_link = shmem_put_link,
|
||||
#ifdef CONFIG_TMPFS_XATTR
|
||||
.setxattr = shmem_setxattr,
|
||||
.getxattr = shmem_getxattr,
|
||||
|
|
Loading…
Reference in a new issue