mirror of
				https://github.com/torvalds/linux.git
				synced 2025-11-04 10:40:15 +02:00 
			
		
		
		
	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 @@ 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,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										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 @@ static int nfs_symlink_filler(struct inode *inode, struct page *page)
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
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 @@ int ovl_permission(struct inode *inode, int mask)
 | 
			
		|||
	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