1 // SPDX-License-Identifier: CDDL-1.0
2 /*
3 * CDDL HEADER START
4 *
5 * The contents of this file are subject to the terms of the
6 * Common Development and Distribution License (the "License").
7 * You may not use this file except in compliance with the License.
8 *
9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10 * or https://opensource.org/licenses/CDDL-1.0.
11 * See the License for the specific language governing permissions
12 * and limitations under the License.
13 *
14 * When distributing Covered Code, include this CDDL HEADER in each
15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16 * If applicable, add the following below this CDDL HEADER, with the
17 * fields enclosed by brackets "[]" replaced with your own identifying
18 * information: Portions Copyright [yyyy] [name of copyright owner]
19 *
20 * CDDL HEADER END
21 */
22 /*
23 * Copyright (c) 2011 Gunnar Beutner
24 * Copyright (c) 2012 Cyril Plisko. All rights reserved.
25 */
26
27
28 #include <sys/file.h>
29 #include <sys/zfs_znode.h>
30 #include <sys/zfs_vnops.h>
31 #include <sys/zfs_ctldir.h>
32 #include <sys/zpl.h>
33
34
35 static int
zpl_encode_fh(struct inode * ip,__u32 * fh,int * max_len,struct inode * parent)36 zpl_encode_fh(struct inode *ip, __u32 *fh, int *max_len, struct inode *parent)
37 {
38 fstrans_cookie_t cookie;
39 ushort_t empty_fid = 0;
40 fid_t *fid;
41 int len_bytes, rc;
42
43 len_bytes = *max_len * sizeof (__u32);
44
45 if (len_bytes < offsetof(fid_t, fid_data)) {
46 fid = (fid_t *)&empty_fid;
47 } else {
48 fid = (fid_t *)fh;
49 fid->fid_len = len_bytes - offsetof(fid_t, fid_data);
50 }
51
52 cookie = spl_fstrans_mark();
53
54 if (zfsctl_is_node(ip))
55 rc = zfsctl_fid(ip, fid);
56 else
57 rc = zfs_fid(ip, fid);
58
59 spl_fstrans_unmark(cookie);
60 len_bytes = offsetof(fid_t, fid_data) + fid->fid_len;
61 *max_len = roundup(len_bytes, sizeof (__u32)) / sizeof (__u32);
62
63 return (rc == 0 ? FILEID_INO32_GEN : 255);
64 }
65
66 static struct dentry *
zpl_fh_to_dentry(struct super_block * sb,struct fid * fh,int fh_len,int fh_type)67 zpl_fh_to_dentry(struct super_block *sb, struct fid *fh,
68 int fh_len, int fh_type)
69 {
70 fid_t *fid = (fid_t *)fh;
71 fstrans_cookie_t cookie;
72 struct inode *ip;
73 int len_bytes, rc;
74
75 len_bytes = fh_len * sizeof (__u32);
76
77 if (fh_type != FILEID_INO32_GEN ||
78 len_bytes < offsetof(fid_t, fid_data) ||
79 len_bytes < offsetof(fid_t, fid_data) + fid->fid_len)
80 return (ERR_PTR(-EINVAL));
81
82 cookie = spl_fstrans_mark();
83 rc = zfs_vget(sb, &ip, fid);
84 spl_fstrans_unmark(cookie);
85
86 if (rc) {
87 /*
88 * If we see ENOENT it might mean that an NFSv4 * client
89 * is using a cached inode value in a file handle and
90 * that the sought after file has had its inode changed
91 * by a third party. So change the error to ESTALE
92 * which will trigger a full lookup by the client and
93 * will find the new filename/inode pair if it still
94 * exists.
95 */
96 if (rc == ENOENT)
97 rc = ESTALE;
98
99 return (ERR_PTR(-rc));
100 }
101
102 ASSERT((ip != NULL) && !IS_ERR(ip));
103
104 return (d_obtain_alias(ip));
105 }
106
107 /*
108 * In case the filesystem contains name longer than 255, we need to override
109 * the default get_name so we don't get buffer overflow. Unfortunately, since
110 * the buffer size is hardcoded in Linux, we will get ESTALE error in this
111 * case.
112 */
113 static int
zpl_get_name(struct dentry * parent,char * name,struct dentry * child)114 zpl_get_name(struct dentry *parent, char *name, struct dentry *child)
115 {
116 cred_t *cr = CRED();
117 fstrans_cookie_t cookie;
118 struct inode *dir = parent->d_inode;
119 struct inode *ip = child->d_inode;
120 int error;
121
122 if (!dir || !S_ISDIR(dir->i_mode))
123 return (-ENOTDIR);
124
125 crhold(cr);
126 cookie = spl_fstrans_mark();
127 spl_inode_lock_shared(dir);
128 error = -zfs_get_name(ITOZ(dir), name, ITOZ(ip));
129 spl_inode_unlock_shared(dir);
130 spl_fstrans_unmark(cookie);
131 crfree(cr);
132
133 return (error);
134 }
135
136 static struct dentry *
zpl_get_parent(struct dentry * child)137 zpl_get_parent(struct dentry *child)
138 {
139 cred_t *cr = CRED();
140 fstrans_cookie_t cookie;
141 znode_t *zp;
142 int error;
143
144 crhold(cr);
145 cookie = spl_fstrans_mark();
146 error = -zfs_lookup(ITOZ(child->d_inode), "..", &zp, 0, cr, NULL, NULL);
147 spl_fstrans_unmark(cookie);
148 crfree(cr);
149 ASSERT3S(error, <=, 0);
150
151 if (error)
152 return (ERR_PTR(error));
153
154 return (d_obtain_alias(ZTOI(zp)));
155 }
156
157 static int
zpl_commit_metadata(struct inode * inode)158 zpl_commit_metadata(struct inode *inode)
159 {
160 cred_t *cr = CRED();
161 fstrans_cookie_t cookie;
162 int error;
163
164 if (zfsctl_is_node(inode))
165 return (0);
166
167 crhold(cr);
168 cookie = spl_fstrans_mark();
169 error = -zfs_fsync(ITOZ(inode), 0, cr);
170 spl_fstrans_unmark(cookie);
171 crfree(cr);
172 ASSERT3S(error, <=, 0);
173
174 return (error);
175 }
176
177 const struct export_operations zpl_export_operations = {
178 .encode_fh = zpl_encode_fh,
179 .fh_to_dentry = zpl_fh_to_dentry,
180 .get_name = zpl_get_name,
181 .get_parent = zpl_get_parent,
182 .commit_metadata = zpl_commit_metadata,
183 };
184