Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 32fb3784 authored by Linus Torvalds's avatar Linus Torvalds
Browse files
Pull vfs RCU symlink updates from Al Viro:
 "Replacement of ->follow_link/->put_link, allowing to stay in RCU mode
  even if the symlink is not an embedded one.

  No changes since the mailbomb on Jan 1"

* 'work.symlinks' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs:
  switch ->get_link() to delayed_call, kill ->put_link()
  kill free_page_put_link()
  teach nfs_get_link() to work in RCU mode
  teach proc_self_get_link()/proc_thread_self_get_link() to work in RCU mode
  teach shmem_get_link() to work in RCU mode
  teach page_get_link() to work in RCU mode
  replace ->follow_link() with new method that could stay in RCU mode
  don't put symlink bodies in pagecache into highmem
  namei: page_getlink() and page_follow_link_light() are the same thing
  ufs: get rid of ->setattr() for symlinks
  udf: don't duplicate page_symlink_inode_operations
  logfs: don't duplicate page_symlink_inode_operations
  switch befs long symlinks to page_symlink_operations
parents 19ccb28e fceef393
Loading
Loading
Loading
Loading
+2 −4
Original line number Original line Diff line number Diff line
@@ -50,8 +50,7 @@ prototypes:
	int (*rename2) (struct inode *, struct dentry *,
	int (*rename2) (struct inode *, struct dentry *,
			struct inode *, struct dentry *, unsigned int);
			struct inode *, struct dentry *, unsigned int);
	int (*readlink) (struct dentry *, char __user *,int);
	int (*readlink) (struct dentry *, char __user *,int);
	const char *(*follow_link) (struct dentry *, void **);
	const char *(*get_link) (struct dentry *, struct inode *, void **);
	void (*put_link) (struct inode *, void *);
	void (*truncate) (struct inode *);
	void (*truncate) (struct inode *);
	int (*permission) (struct inode *, int, unsigned int);
	int (*permission) (struct inode *, int, unsigned int);
	int (*get_acl)(struct inode *, int);
	int (*get_acl)(struct inode *, int);
@@ -83,8 +82,7 @@ rmdir: yes (both) (see below)
rename:		yes (all)	(see below)
rename:		yes (all)	(see below)
rename2:	yes (all)	(see below)
rename2:	yes (all)	(see below)
readlink:	no
readlink:	no
follow_link:	no
get_link:	no
put_link:	no
setattr:	yes
setattr:	yes
permission:	no (may not block if called in rcu-walk mode)
permission:	no (may not block if called in rcu-walk mode)
get_acl:	no
get_acl:	no
+17 −0
Original line number Original line Diff line number Diff line
@@ -504,3 +504,20 @@ in your dentry operations instead.
[mandatory]
[mandatory]
	__fd_install() & fd_install() can now sleep. Callers should not
	__fd_install() & fd_install() can now sleep. Callers should not
	hold a spinlock	or other resources that do not allow a schedule.
	hold a spinlock	or other resources that do not allow a schedule.
--
[mandatory]
	any symlink that might use page_follow_link_light/page_put_link() must
	have inode_nohighmem(inode) called before anything might start playing with
	its pagecache.
--
[mandatory]
	->follow_link() is replaced with ->get_link(); same API, except that
		* ->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().
+10 −11
Original line number Original line Diff line number Diff line
@@ -350,8 +350,8 @@ struct inode_operations {
	int (*rename2) (struct inode *, struct dentry *,
	int (*rename2) (struct inode *, struct dentry *,
			struct inode *, struct dentry *, unsigned int);
			struct inode *, struct dentry *, unsigned int);
	int (*readlink) (struct dentry *, char __user *,int);
	int (*readlink) (struct dentry *, char __user *,int);
	const char *(*follow_link) (struct dentry *, void **);
	const char *(*get_link) (struct dentry *, struct inode *,
	void (*put_link) (struct inode *, void *);
				 struct delayed_call *);
	int (*permission) (struct inode *, int);
	int (*permission) (struct inode *, int);
	int (*get_acl)(struct inode *, int);
	int (*get_acl)(struct inode *, int);
	int (*setattr) (struct dentry *, struct iattr *);
	int (*setattr) (struct dentry *, struct iattr *);
@@ -434,20 +434,19 @@ otherwise noted.
  readlink: called by the readlink(2) system call. Only required if
  readlink: called by the readlink(2) system call. Only required if
	you want to support reading symbolic links
	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
	inode it points to.  Only required if you want to support
	symbolic links.  This method returns the symlink body
	symbolic links.  This method returns the symlink body
	to traverse (and possibly resets the current position with
	to traverse (and possibly resets the current position with
	nd_jump_link()).  If the body won't go away until the inode
	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
	is gone, nothing else is needed; if it needs to be otherwise
	pinned, the data needed to release whatever we'd grabbed
	pinned, arrange for its release by having get_link(..., ..., done)
	is to be stored in void * variable passed by address to
	do set_delayed_call(done, destructor, argument).
	follow_link() instance.
	In that case destructor(argument) will be called once VFS is

	done with the body you've returned.
  put_link: called by the VFS to release resources allocated by
	May be called in RCU mode; that is indicated by NULL dentry
	follow_link().  The cookie stored by follow_link() is passed
	argument.  If request can't be handled without leaving RCU mode,
	to this method as the last parameter; only called when
	have it return ERR_PTR(-ECHILD).
	cookie isn't NULL.


  permission: called by the VFS to check for access rights on a POSIX-like
  permission: called by the VFS to check for access rights on a POSIX-like
  	filesystem.
  	filesystem.
+13 −11
Original line number Original line Diff line number Diff line
@@ -118,12 +118,20 @@ static int ll_readlink_internal(struct inode *inode,
	return rc;
	return rc;
}
}


static const char *ll_follow_link(struct dentry *dentry, void **cookie)
static void ll_put_link(void *p)
{
	ptlrpc_req_finished(p);
}

static const char *ll_get_link(struct dentry *dentry,
			       struct inode *inode,
			       struct delayed_call *done)
{
{
	struct inode *inode = d_inode(dentry);
	struct ptlrpc_request *request = NULL;
	struct ptlrpc_request *request = NULL;
	int rc;
	int rc;
	char *symname = NULL;
	char *symname = NULL;
	if (!dentry)
		return ERR_PTR(-ECHILD);


	CDEBUG(D_VFSTRACE, "VFS Op\n");
	CDEBUG(D_VFSTRACE, "VFS Op\n");
	ll_inode_size_lock(inode);
	ll_inode_size_lock(inode);
@@ -135,22 +143,16 @@ static const char *ll_follow_link(struct dentry *dentry, void **cookie)
	}
	}


	/* symname may contain a pointer to the request message buffer,
	/* 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;
	return symname;
}
}


static void ll_put_link(struct inode *unused, void *cookie)
{
	ptlrpc_req_finished(cookie);
}

struct inode_operations ll_fast_symlink_inode_operations = {
struct inode_operations ll_fast_symlink_inode_operations = {
	.readlink	= generic_readlink,
	.readlink	= generic_readlink,
	.setattr	= ll_setattr,
	.setattr	= ll_setattr,
	.follow_link	= ll_follow_link,
	.get_link	= ll_get_link,
	.put_link	= ll_put_link,
	.getattr	= ll_getattr,
	.getattr	= ll_getattr,
	.permission	= ll_inode_permission,
	.permission	= ll_inode_permission,
	.setxattr	= ll_setxattr,
	.setxattr	= ll_setxattr,
+16 −8
Original line number Original line Diff line number Diff line
@@ -1223,18 +1223,26 @@ ino_t v9fs_qid2ino(struct p9_qid *qid)
}
}


/**
/**
 * v9fs_vfs_follow_link - follow a symlink path
 * v9fs_vfs_get_link - follow a symlink path
 * @dentry: dentry for symlink
 * @dentry: dentry for symlink
 * @cookie: place to pass the data to put_link()
 * @inode: inode for symlink
 * @done: delayed call for when we are done with the return value
 */
 */


static const char *v9fs_vfs_follow_link(struct dentry *dentry, void **cookie)
static const char *v9fs_vfs_get_link(struct dentry *dentry,
				     struct inode *inode,
				     struct delayed_call *done)
{
{
	struct v9fs_session_info *v9ses = v9fs_dentry2v9ses(dentry);
	struct v9fs_session_info *v9ses;
	struct p9_fid *fid = v9fs_fid_lookup(dentry);
	struct p9_fid *fid;
	struct p9_wstat *st;
	struct p9_wstat *st;
	char *res;
	char *res;


	if (!dentry)
		return ERR_PTR(-ECHILD);

	v9ses = v9fs_dentry2v9ses(dentry);
	fid = v9fs_fid_lookup(dentry);
	p9_debug(P9_DEBUG_VFS, "%pd\n", dentry);
	p9_debug(P9_DEBUG_VFS, "%pd\n", dentry);


	if (IS_ERR(fid))
	if (IS_ERR(fid))
@@ -1259,7 +1267,8 @@ static const char *v9fs_vfs_follow_link(struct dentry *dentry, void **cookie)


	p9stat_free(st);
	p9stat_free(st);
	kfree(st);
	kfree(st);
	return *cookie = res;
	set_delayed_call(done, kfree_link, res);
	return res;
}
}


/**
/**
@@ -1452,8 +1461,7 @@ static const struct inode_operations v9fs_file_inode_operations = {


static const struct inode_operations v9fs_symlink_inode_operations = {
static const struct inode_operations v9fs_symlink_inode_operations = {
	.readlink = generic_readlink,
	.readlink = generic_readlink,
	.follow_link = v9fs_vfs_follow_link,
	.get_link = v9fs_vfs_get_link,
	.put_link = kfree_put_link,
	.getattr = v9fs_vfs_getattr,
	.getattr = v9fs_vfs_getattr,
	.setattr = v9fs_vfs_setattr,
	.setattr = v9fs_vfs_setattr,
};
};
Loading