summaryrefslogtreecommitdiffstats
path: root/module/zfs
diff options
context:
space:
mode:
authorBrian Behlendorf <[email protected]>2016-01-14 13:25:10 -0500
committerBrian Behlendorf <[email protected]>2016-01-29 09:52:13 -0800
commitb3c9e2caf570d0c7093de33fb5280541865b32d9 (patch)
tree06453021d6d28fd9f4dd045cfac647e3aa5a1989 /module/zfs
parentf00a5734f61347446fd5175801b03ad45373b8cf (diff)
Linux 4.5 compat: get_link() / put_link()
The follow_link() interface was retired in favor of get_link(). In the process of phasing in get_link() the Linux kernel went through two different versions. The first of which depended on put_link() and the final version on a delayed done function. - Improved configure checks for .follow_link, .get_link, .put_link. - Interfaces checked from newest to oldest. - Strict checking for each possible known interface. - Configure fails when no known interface is available. - Both versions .get_link are detected and supported as well two previous versions of .follow_link. Signed-off-by: Brian Behlendorf <[email protected]> Signed-off-by: Tim Chase <[email protected]> Signed-off-by: Chunwei Chen <[email protected]> Issue #4228
Diffstat (limited to 'module/zfs')
-rw-r--r--module/zfs/zpl_inode.c125
1 files changed, 92 insertions, 33 deletions
diff --git a/module/zfs/zpl_inode.c b/module/zfs/zpl_inode.c
index e0e8ee3ac..bd0d5129c 100644
--- a/module/zfs/zpl_inode.c
+++ b/module/zfs/zpl_inode.c
@@ -339,26 +339,42 @@ zpl_symlink(struct inode *dir, struct dentry *dentry, const char *name)
return (error);
}
-#ifdef HAVE_FOLLOW_LINK_NAMEIDATA
-static void *
-zpl_follow_link(struct dentry *dentry, struct nameidata *nd)
-#else
-const char *
-zpl_follow_link(struct dentry *dentry, void **symlink_cookie)
+#if defined(HAVE_PUT_LINK_COOKIE)
+static void
+zpl_put_link(struct inode *unused, void *cookie)
+{
+ kmem_free(cookie, MAXPATHLEN);
+}
+#elif defined(HAVE_PUT_LINK_NAMEIDATA)
+static void
+zpl_put_link(struct dentry *dentry, struct nameidata *nd, void *ptr)
+{
+ const char *link = nd_get_link(nd);
+
+ if (!IS_ERR(link))
+ kmem_free(link, MAXPATHLEN);
+}
+#elif defined(HAVE_PUT_LINK_DELAYED)
+static void
+zpl_put_link(void *ptr)
+{
+ kmem_free(ptr, MAXPATHLEN);
+}
#endif
+
+static int
+zpl_get_link_common(struct dentry *dentry, struct inode *ip, char **link)
{
+ fstrans_cookie_t cookie;
cred_t *cr = CRED();
- struct inode *ip = dentry->d_inode;
struct iovec iov;
uio_t uio;
- char *link;
int error;
- fstrans_cookie_t cookie;
crhold(cr);
-
+ *link = NULL;
iov.iov_len = MAXPATHLEN;
- iov.iov_base = link = kmem_zalloc(MAXPATHLEN, KM_SLEEP);
+ iov.iov_base = kmem_zalloc(MAXPATHLEN, KM_SLEEP);
uio.uio_iov = &iov;
uio.uio_iovcnt = 1;
@@ -369,41 +385,78 @@ zpl_follow_link(struct dentry *dentry, void **symlink_cookie)
cookie = spl_fstrans_mark();
error = -zfs_readlink(ip, &uio, cr);
spl_fstrans_unmark(cookie);
-
- if (error)
- kmem_free(link, MAXPATHLEN);
-
crfree(cr);
-#ifdef HAVE_FOLLOW_LINK_NAMEIDATA
if (error)
- nd_set_link(nd, ERR_PTR(error));
+ kmem_free(iov.iov_base, MAXPATHLEN);
else
- nd_set_link(nd, link);
+ *link = iov.iov_base;
- return (NULL);
-#else
+ return (error);
+}
+
+#if defined(HAVE_GET_LINK_DELAYED)
+const char *
+zpl_get_link(struct dentry *dentry, struct inode *inode,
+ struct delayed_call *done)
+{
+ char *link = NULL;
+ int error;
+
+ if (!dentry)
+ return (ERR_PTR(-ECHILD));
+
+ error = zpl_get_link_common(dentry, inode, &link);
if (error)
return (ERR_PTR(error));
- else
- return (*symlink_cookie = link);
-#endif
+
+ set_delayed_call(done, zpl_put_link, link);
+
+ return (link);
}
+#elif defined(HAVE_GET_LINK_COOKIE)
+const char *
+zpl_get_link(struct dentry *dentry, struct inode *inode, void **cookie)
+{
+ char *link = NULL;
+ int error;
-#ifdef HAVE_PUT_LINK_NAMEIDATA
-static void
-zpl_put_link(struct dentry *dentry, struct nameidata *nd, void *ptr)
+ if (!dentry)
+ return (ERR_PTR(-ECHILD));
+
+ error = zpl_get_link_common(dentry, inode, &link);
+ if (error)
+ return (ERR_PTR(error));
+
+ return (*cookie = link);
+}
+#elif defined(HAVE_FOLLOW_LINK_COOKIE)
+const char *
+zpl_follow_link(struct dentry *dentry, void **cookie)
{
- const char *link = nd_get_link(nd);
+ char *link = NULL;
+ int error;
- if (!IS_ERR(link))
- kmem_free(link, MAXPATHLEN);
+ error = zpl_get_link_common(dentry, dentry->d_inode, &link);
+ if (error)
+ return (ERR_PTR(error));
+
+ return (*cookie = link);
}
-#else
-static void
-zpl_put_link(struct inode *unused, void *symlink_cookie)
+#elif defined(HAVE_FOLLOW_LINK_NAMEIDATA)
+static void *
+zpl_follow_link(struct dentry *dentry, struct nameidata *nd)
{
- kmem_free(symlink_cookie, MAXPATHLEN);
+ char *link = NULL;
+ int error;
+
+ error = zpl_get_link_common(dentry, dentry->d_inode, &link);
+ if (error)
+ nd_set_link(nd, ERR_PTR(error));
+ else
+ nd_set_link(nd, link);
+
+ return (NULL);
}
#endif
@@ -591,8 +644,14 @@ const struct inode_operations zpl_dir_inode_operations = {
const struct inode_operations zpl_symlink_inode_operations = {
.readlink = generic_readlink,
+#if defined(HAVE_GET_LINK_DELAYED) || defined(HAVE_GET_LINK_COOKIE)
+ .get_link = zpl_get_link,
+#elif defined(HAVE_FOLLOW_LINK_COOKIE) || defined(HAVE_FOLLOW_LINK_NAMEIDATA)
.follow_link = zpl_follow_link,
+#endif
+#if defined(HAVE_PUT_LINK_COOKIE) || defined(HAVE_PUT_LINK_NAMEIDATA)
.put_link = zpl_put_link,
+#endif
.setattr = zpl_setattr,
.getattr = zpl_getattr,
.setxattr = generic_setxattr,