]>
Commit | Line | Data |
---|---|---|
ebe7e575 BB |
1 | /* |
2 | * CDDL HEADER START | |
3 | * | |
4 | * The contents of this file are subject to the terms of the | |
5 | * Common Development and Distribution License (the "License"). | |
6 | * You may not use this file except in compliance with the License. | |
7 | * | |
8 | * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE | |
9 | * or http://www.opensolaris.org/os/licensing. | |
10 | * See the License for the specific language governing permissions | |
11 | * and limitations under the License. | |
12 | * | |
13 | * When distributing Covered Code, include this CDDL HEADER in each | |
14 | * file and include the License file at usr/src/OPENSOLARIS.LICENSE. | |
15 | * If applicable, add the following below this CDDL HEADER, with the | |
16 | * fields enclosed by brackets "[]" replaced with your own identifying | |
17 | * information: Portions Copyright [yyyy] [name of copyright owner] | |
18 | * | |
19 | * CDDL HEADER END | |
20 | */ | |
21 | /* | |
22 | * Copyright (C) 2011 Lawrence Livermore National Security, LLC. | |
23 | * Produced at Lawrence Livermore National Laboratory (cf, DISCLAIMER). | |
24 | * LLNL-CODE-403049. | |
25 | * Rewritten for Linux by: | |
26 | * Rohan Puri <rohan.puri15@gmail.com> | |
27 | * Brian Behlendorf <behlendorf1@llnl.gov> | |
28 | */ | |
29 | ||
657ce253 | 30 | #include <sys/zfs_znode.h> |
ebe7e575 BB |
31 | #include <sys/zfs_vfsops.h> |
32 | #include <sys/zfs_vnops.h> | |
ebe7e575 BB |
33 | #include <sys/zfs_ctldir.h> |
34 | #include <sys/zpl.h> | |
35 | ||
36 | /* | |
37 | * Common open routine. Disallow any write access. | |
38 | */ | |
39 | /* ARGSUSED */ | |
40 | static int | |
41 | zpl_common_open(struct inode *ip, struct file *filp) | |
42 | { | |
43 | if (filp->f_mode & FMODE_WRITE) | |
44 | return (-EACCES); | |
45 | ||
d1d7e268 | 46 | return (generic_file_open(ip, filp)); |
ebe7e575 BB |
47 | } |
48 | ||
ebe7e575 BB |
49 | /* |
50 | * Get root directory contents. | |
51 | */ | |
52 | static int | |
9464b959 | 53 | zpl_root_iterate(struct file *filp, zpl_dir_context_t *ctx) |
ebe7e575 | 54 | { |
0037b49e | 55 | zfsvfs_t *zfsvfs = ITOZSB(file_inode(filp)); |
ebe7e575 BB |
56 | int error = 0; |
57 | ||
4352edaa | 58 | ZPL_ENTER(zfsvfs); |
ebe7e575 | 59 | |
9464b959 | 60 | if (!zpl_dir_emit_dots(filp, ctx)) |
0f37d0c8 | 61 | goto out; |
ebe7e575 | 62 | |
0f37d0c8 | 63 | if (ctx->pos == 2) { |
9464b959 BB |
64 | if (!zpl_dir_emit(ctx, ZFS_SNAPDIR_NAME, |
65 | strlen(ZFS_SNAPDIR_NAME), ZFSCTL_INO_SNAPDIR, DT_DIR)) | |
ebe7e575 BB |
66 | goto out; |
67 | ||
0f37d0c8 RY |
68 | ctx->pos++; |
69 | } | |
ebe7e575 | 70 | |
0f37d0c8 | 71 | if (ctx->pos == 3) { |
9464b959 BB |
72 | if (!zpl_dir_emit(ctx, ZFS_SHAREDIR_NAME, |
73 | strlen(ZFS_SHAREDIR_NAME), ZFSCTL_INO_SHARES, DT_DIR)) | |
ebe7e575 BB |
74 | goto out; |
75 | ||
0f37d0c8 | 76 | ctx->pos++; |
ebe7e575 BB |
77 | } |
78 | out: | |
4352edaa | 79 | ZPL_EXIT(zfsvfs); |
ebe7e575 BB |
80 | |
81 | return (error); | |
82 | } | |
83 | ||
9baaa7de | 84 | #if !defined(HAVE_VFS_ITERATE) && !defined(HAVE_VFS_ITERATE_SHARED) |
0f37d0c8 RY |
85 | static int |
86 | zpl_root_readdir(struct file *filp, void *dirent, filldir_t filldir) | |
87 | { | |
9464b959 BB |
88 | zpl_dir_context_t ctx = |
89 | ZPL_DIR_CONTEXT_INIT(dirent, filldir, filp->f_pos); | |
0f37d0c8 RY |
90 | int error; |
91 | ||
92 | error = zpl_root_iterate(filp, &ctx); | |
93 | filp->f_pos = ctx.pos; | |
94 | ||
95 | return (error); | |
96 | } | |
9464b959 | 97 | #endif /* !HAVE_VFS_ITERATE && !HAVE_VFS_ITERATE_SHARED */ |
0f37d0c8 | 98 | |
ebe7e575 BB |
99 | /* |
100 | * Get root directory attributes. | |
101 | */ | |
102 | /* ARGSUSED */ | |
103 | static int | |
e2a82961 CK |
104 | #ifdef HAVE_USERNS_IOPS_GETATTR |
105 | zpl_root_getattr_impl(struct user_namespace *user_ns, | |
106 | const struct path *path, struct kstat *stat, u32 request_mask, | |
107 | unsigned int query_flags) | |
108 | #else | |
a3478c07 OF |
109 | zpl_root_getattr_impl(const struct path *path, struct kstat *stat, |
110 | u32 request_mask, unsigned int query_flags) | |
e2a82961 | 111 | #endif |
ebe7e575 | 112 | { |
2946a1a1 BB |
113 | struct inode *ip = path->dentry->d_inode; |
114 | ||
e2a82961 CK |
115 | #if defined(HAVE_GENERIC_FILLATTR_USERNS) && defined(HAVE_USERNS_IOPS_GETATTR) |
116 | generic_fillattr(user_ns, ip, stat); | |
117 | #else | |
2946a1a1 | 118 | generic_fillattr(ip, stat); |
e2a82961 | 119 | #endif |
2946a1a1 | 120 | stat->atime = current_time(ip); |
ebe7e575 | 121 | |
a3478c07 | 122 | return (0); |
ebe7e575 | 123 | } |
a3478c07 | 124 | ZPL_GETATTR_WRAPPER(zpl_root_getattr); |
ebe7e575 BB |
125 | |
126 | static struct dentry * | |
8f195a90 | 127 | zpl_root_lookup(struct inode *dip, struct dentry *dentry, unsigned int flags) |
ebe7e575 BB |
128 | { |
129 | cred_t *cr = CRED(); | |
130 | struct inode *ip; | |
131 | int error; | |
132 | ||
133 | crhold(cr); | |
134 | error = -zfsctl_root_lookup(dip, dname(dentry), &ip, 0, cr, NULL, NULL); | |
135 | ASSERT3S(error, <=, 0); | |
136 | crfree(cr); | |
137 | ||
138 | if (error) { | |
139 | if (error == -ENOENT) | |
d1d7e268 | 140 | return (d_splice_alias(NULL, dentry)); |
ebe7e575 | 141 | else |
d1d7e268 | 142 | return (ERR_PTR(error)); |
ebe7e575 BB |
143 | } |
144 | ||
d1d7e268 | 145 | return (d_splice_alias(ip, dentry)); |
ebe7e575 BB |
146 | } |
147 | ||
148 | /* | |
149 | * The '.zfs' control directory file and inode operations. | |
150 | */ | |
151 | const struct file_operations zpl_fops_root = { | |
152 | .open = zpl_common_open, | |
153 | .llseek = generic_file_llseek, | |
154 | .read = generic_read_dir, | |
9baaa7de CC |
155 | #ifdef HAVE_VFS_ITERATE_SHARED |
156 | .iterate_shared = zpl_root_iterate, | |
157 | #elif defined(HAVE_VFS_ITERATE) | |
0f37d0c8 RY |
158 | .iterate = zpl_root_iterate, |
159 | #else | |
ebe7e575 | 160 | .readdir = zpl_root_readdir, |
0f37d0c8 | 161 | #endif |
ebe7e575 BB |
162 | }; |
163 | ||
164 | const struct inode_operations zpl_ops_root = { | |
165 | .lookup = zpl_root_lookup, | |
166 | .getattr = zpl_root_getattr, | |
167 | }; | |
168 | ||
f1a05fa1 NB |
169 | static struct vfsmount * |
170 | zpl_snapdir_automount(struct path *path) | |
171 | { | |
f1a05fa1 NB |
172 | int error; |
173 | ||
278bee93 | 174 | error = -zfsctl_snapshot_mount(path, 0); |
f1a05fa1 | 175 | if (error) |
d1d7e268 | 176 | return (ERR_PTR(error)); |
f1a05fa1 NB |
177 | |
178 | /* | |
179 | * Rather than returning the new vfsmount for the snapshot we must | |
180 | * return NULL to indicate a mount collision. This is done because | |
181 | * the user space mount calls do_add_mount() which adds the vfsmount | |
182 | * to the name space. If we returned the new mount here it would be | |
183 | * added again to the vfsmount list resulting in list corruption. | |
184 | */ | |
185 | return (NULL); | |
186 | } | |
f1a05fa1 NB |
187 | |
188 | /* | |
278bee93 BB |
189 | * Negative dentries must always be revalidated so newly created snapshots |
190 | * can be detected and automounted. Normal dentries should be kept because | |
191 | * as of the 3.18 kernel revaliding the mountpoint dentry will result in | |
192 | * the snapshot being immediately unmounted. | |
f1a05fa1 NB |
193 | */ |
194 | static int | |
195 | #ifdef HAVE_D_REVALIDATE_NAMEIDATA | |
196 | zpl_snapdir_revalidate(struct dentry *dentry, struct nameidata *i) | |
197 | #else | |
198 | zpl_snapdir_revalidate(struct dentry *dentry, unsigned int flags) | |
199 | #endif | |
200 | { | |
278bee93 | 201 | return (!!dentry->d_inode); |
f1a05fa1 NB |
202 | } |
203 | ||
18168da7 | 204 | static const dentry_operations_t zpl_dops_snapdirs = { |
f1a05fa1 NB |
205 | /* |
206 | * Auto mounting of snapshots is only supported for 2.6.37 and | |
207 | * newer kernels. Prior to this kernel the ops->follow_link() | |
208 | * callback was used as a hack to trigger the mount. The | |
209 | * resulting vfsmount was then explicitly grafted in to the | |
210 | * name space. While it might be possible to add compatibility | |
211 | * code to accomplish this it would require considerable care. | |
212 | */ | |
f1a05fa1 | 213 | .d_automount = zpl_snapdir_automount, |
f1a05fa1 NB |
214 | .d_revalidate = zpl_snapdir_revalidate, |
215 | }; | |
216 | ||
ebe7e575 | 217 | static struct dentry * |
8f195a90 YS |
218 | zpl_snapdir_lookup(struct inode *dip, struct dentry *dentry, |
219 | unsigned int flags) | |
ebe7e575 | 220 | { |
7fad6290 | 221 | fstrans_cookie_t cookie; |
ebe7e575 | 222 | cred_t *cr = CRED(); |
f1a05fa1 | 223 | struct inode *ip = NULL; |
ebe7e575 BB |
224 | int error; |
225 | ||
226 | crhold(cr); | |
7fad6290 | 227 | cookie = spl_fstrans_mark(); |
ebe7e575 BB |
228 | error = -zfsctl_snapdir_lookup(dip, dname(dentry), &ip, |
229 | 0, cr, NULL, NULL); | |
230 | ASSERT3S(error, <=, 0); | |
7fad6290 | 231 | spl_fstrans_unmark(cookie); |
ebe7e575 BB |
232 | crfree(cr); |
233 | ||
f1a05fa1 | 234 | if (error && error != -ENOENT) |
d1d7e268 | 235 | return (ERR_PTR(error)); |
ebe7e575 | 236 | |
f1a05fa1 | 237 | ASSERT(error == 0 || ip == NULL); |
bf01b5e6 | 238 | d_clear_d_op(dentry); |
f1a05fa1 | 239 | d_set_d_op(dentry, &zpl_dops_snapdirs); |
278bee93 | 240 | dentry->d_flags |= DCACHE_NEED_AUTOMOUNT; |
ebe7e575 | 241 | |
d1d7e268 | 242 | return (d_splice_alias(ip, dentry)); |
ebe7e575 BB |
243 | } |
244 | ||
ebe7e575 | 245 | static int |
9464b959 | 246 | zpl_snapdir_iterate(struct file *filp, zpl_dir_context_t *ctx) |
ebe7e575 | 247 | { |
0037b49e | 248 | zfsvfs_t *zfsvfs = ITOZSB(file_inode(filp)); |
7fad6290 | 249 | fstrans_cookie_t cookie; |
ebe7e575 | 250 | char snapname[MAXNAMELEN]; |
ebe7e575 | 251 | boolean_t case_conflict; |
7fad6290 | 252 | uint64_t id, pos; |
ebe7e575 BB |
253 | int error = 0; |
254 | ||
4352edaa | 255 | ZPL_ENTER(zfsvfs); |
7fad6290 | 256 | cookie = spl_fstrans_mark(); |
ebe7e575 | 257 | |
9464b959 | 258 | if (!zpl_dir_emit_dots(filp, ctx)) |
0f37d0c8 | 259 | goto out; |
ebe7e575 | 260 | |
9bd14b87 TP |
261 | /* Start the position at 0 if it already emitted . and .. */ |
262 | pos = (ctx->pos == 2 ? 0 : ctx->pos); | |
0f37d0c8 | 263 | while (error == 0) { |
0037b49e BB |
264 | dsl_pool_config_enter(dmu_objset_pool(zfsvfs->z_os), FTAG); |
265 | error = -dmu_snapshot_list_next(zfsvfs->z_os, MAXNAMELEN, | |
7fad6290 | 266 | snapname, &id, &pos, &case_conflict); |
0037b49e | 267 | dsl_pool_config_exit(dmu_objset_pool(zfsvfs->z_os), FTAG); |
ebe7e575 BB |
268 | if (error) |
269 | goto out; | |
270 | ||
9464b959 | 271 | if (!zpl_dir_emit(ctx, snapname, strlen(snapname), |
0f37d0c8 RY |
272 | ZFSCTL_INO_SHARES - id, DT_DIR)) |
273 | goto out; | |
5f15fa22 | 274 | |
7fad6290 | 275 | ctx->pos = pos; |
ebe7e575 BB |
276 | } |
277 | out: | |
7fad6290 | 278 | spl_fstrans_unmark(cookie); |
4352edaa | 279 | ZPL_EXIT(zfsvfs); |
ebe7e575 BB |
280 | |
281 | if (error == -ENOENT) | |
282 | return (0); | |
283 | ||
284 | return (error); | |
285 | } | |
286 | ||
9baaa7de | 287 | #if !defined(HAVE_VFS_ITERATE) && !defined(HAVE_VFS_ITERATE_SHARED) |
0f37d0c8 RY |
288 | static int |
289 | zpl_snapdir_readdir(struct file *filp, void *dirent, filldir_t filldir) | |
290 | { | |
9464b959 BB |
291 | zpl_dir_context_t ctx = |
292 | ZPL_DIR_CONTEXT_INIT(dirent, filldir, filp->f_pos); | |
0f37d0c8 RY |
293 | int error; |
294 | ||
295 | error = zpl_snapdir_iterate(filp, &ctx); | |
296 | filp->f_pos = ctx.pos; | |
297 | ||
298 | return (error); | |
299 | } | |
9464b959 | 300 | #endif /* !HAVE_VFS_ITERATE && !HAVE_VFS_ITERATE_SHARED */ |
0f37d0c8 | 301 | |
b8d9e264 | 302 | static int |
e2a82961 CK |
303 | #ifdef HAVE_IOPS_RENAME_USERNS |
304 | zpl_snapdir_rename2(struct user_namespace *user_ns, struct inode *sdip, | |
305 | struct dentry *sdentry, struct inode *tdip, struct dentry *tdentry, | |
306 | unsigned int flags) | |
307 | #else | |
b8d9e264 CC |
308 | zpl_snapdir_rename2(struct inode *sdip, struct dentry *sdentry, |
309 | struct inode *tdip, struct dentry *tdentry, unsigned int flags) | |
e2a82961 | 310 | #endif |
ebe7e575 BB |
311 | { |
312 | cred_t *cr = CRED(); | |
313 | int error; | |
314 | ||
b8d9e264 CC |
315 | /* We probably don't want to support renameat2(2) in ctldir */ |
316 | if (flags) | |
317 | return (-EINVAL); | |
318 | ||
ebe7e575 BB |
319 | crhold(cr); |
320 | error = -zfsctl_snapdir_rename(sdip, dname(sdentry), | |
321 | tdip, dname(tdentry), cr, 0); | |
322 | ASSERT3S(error, <=, 0); | |
323 | crfree(cr); | |
324 | ||
325 | return (error); | |
326 | } | |
327 | ||
e2a82961 | 328 | #if !defined(HAVE_RENAME_WANTS_FLAGS) && !defined(HAVE_IOPS_RENAME_USERNS) |
b8d9e264 CC |
329 | static int |
330 | zpl_snapdir_rename(struct inode *sdip, struct dentry *sdentry, | |
331 | struct inode *tdip, struct dentry *tdentry) | |
332 | { | |
333 | return (zpl_snapdir_rename2(sdip, sdentry, tdip, tdentry, 0)); | |
334 | } | |
335 | #endif | |
336 | ||
ebe7e575 BB |
337 | static int |
338 | zpl_snapdir_rmdir(struct inode *dip, struct dentry *dentry) | |
339 | { | |
340 | cred_t *cr = CRED(); | |
341 | int error; | |
342 | ||
343 | crhold(cr); | |
344 | error = -zfsctl_snapdir_remove(dip, dname(dentry), cr, 0); | |
345 | ASSERT3S(error, <=, 0); | |
346 | crfree(cr); | |
347 | ||
348 | return (error); | |
349 | } | |
350 | ||
351 | static int | |
e2a82961 CK |
352 | #ifdef HAVE_IOPS_MKDIR_USERNS |
353 | zpl_snapdir_mkdir(struct user_namespace *user_ns, struct inode *dip, | |
354 | struct dentry *dentry, umode_t mode) | |
355 | #else | |
066e8252 | 356 | zpl_snapdir_mkdir(struct inode *dip, struct dentry *dentry, umode_t mode) |
e2a82961 | 357 | #endif |
ebe7e575 BB |
358 | { |
359 | cred_t *cr = CRED(); | |
360 | vattr_t *vap; | |
361 | struct inode *ip; | |
362 | int error; | |
363 | ||
364 | crhold(cr); | |
d1d7e268 | 365 | vap = kmem_zalloc(sizeof (vattr_t), KM_SLEEP); |
7b3e34ba | 366 | zpl_vap_init(vap, dip, mode | S_IFDIR, cr); |
ebe7e575 BB |
367 | |
368 | error = -zfsctl_snapdir_mkdir(dip, dname(dentry), vap, &ip, cr, 0); | |
369 | if (error == 0) { | |
bf01b5e6 | 370 | d_clear_d_op(dentry); |
f1a05fa1 | 371 | d_set_d_op(dentry, &zpl_dops_snapdirs); |
ebe7e575 BB |
372 | d_instantiate(dentry, ip); |
373 | } | |
374 | ||
d1d7e268 | 375 | kmem_free(vap, sizeof (vattr_t)); |
ebe7e575 BB |
376 | ASSERT3S(error, <=, 0); |
377 | crfree(cr); | |
378 | ||
379 | return (error); | |
380 | } | |
381 | ||
ebe7e575 BB |
382 | /* |
383 | * Get snapshot directory attributes. | |
384 | */ | |
385 | /* ARGSUSED */ | |
386 | static int | |
e2a82961 CK |
387 | #ifdef HAVE_USERNS_IOPS_GETATTR |
388 | zpl_snapdir_getattr_impl(struct user_namespace *user_ns, | |
389 | const struct path *path, struct kstat *stat, u32 request_mask, | |
390 | unsigned int query_flags) | |
391 | #else | |
a3478c07 OF |
392 | zpl_snapdir_getattr_impl(const struct path *path, struct kstat *stat, |
393 | u32 request_mask, unsigned int query_flags) | |
e2a82961 | 394 | #endif |
ebe7e575 | 395 | { |
2946a1a1 BB |
396 | struct inode *ip = path->dentry->d_inode; |
397 | zfsvfs_t *zfsvfs = ITOZSB(ip); | |
ebe7e575 | 398 | |
4352edaa | 399 | ZPL_ENTER(zfsvfs); |
e2a82961 CK |
400 | #if defined(HAVE_GENERIC_FILLATTR_USERNS) && defined(HAVE_USERNS_IOPS_GETATTR) |
401 | generic_fillattr(user_ns, ip, stat); | |
402 | #else | |
2946a1a1 | 403 | generic_fillattr(ip, stat); |
e2a82961 | 404 | #endif |
a3478c07 | 405 | |
278bee93 | 406 | stat->nlink = stat->size = 2; |
0037b49e | 407 | stat->ctime = stat->mtime = dmu_objset_snap_cmtime(zfsvfs->z_os); |
2946a1a1 | 408 | stat->atime = current_time(ip); |
4352edaa | 409 | ZPL_EXIT(zfsvfs); |
ebe7e575 | 410 | |
a3478c07 | 411 | return (0); |
ebe7e575 | 412 | } |
a3478c07 | 413 | ZPL_GETATTR_WRAPPER(zpl_snapdir_getattr); |
ebe7e575 BB |
414 | |
415 | /* | |
416 | * The '.zfs/snapshot' directory file operations. These mainly control | |
417 | * generating the list of available snapshots when doing an 'ls' in the | |
418 | * directory. See zpl_snapdir_readdir(). | |
419 | */ | |
420 | const struct file_operations zpl_fops_snapdir = { | |
421 | .open = zpl_common_open, | |
422 | .llseek = generic_file_llseek, | |
423 | .read = generic_read_dir, | |
9baaa7de CC |
424 | #ifdef HAVE_VFS_ITERATE_SHARED |
425 | .iterate_shared = zpl_snapdir_iterate, | |
426 | #elif defined(HAVE_VFS_ITERATE) | |
0f37d0c8 RY |
427 | .iterate = zpl_snapdir_iterate, |
428 | #else | |
ebe7e575 | 429 | .readdir = zpl_snapdir_readdir, |
0f37d0c8 RY |
430 | #endif |
431 | ||
ebe7e575 BB |
432 | }; |
433 | ||
434 | /* | |
435 | * The '.zfs/snapshot' directory inode operations. These mainly control | |
436 | * creating an inode for a snapshot directory and initializing the needed | |
437 | * infrastructure to automount the snapshot. See zpl_snapdir_lookup(). | |
438 | */ | |
439 | const struct inode_operations zpl_ops_snapdir = { | |
440 | .lookup = zpl_snapdir_lookup, | |
441 | .getattr = zpl_snapdir_getattr, | |
e2a82961 | 442 | #if defined(HAVE_RENAME_WANTS_FLAGS) || defined(HAVE_IOPS_RENAME_USERNS) |
b8d9e264 CC |
443 | .rename = zpl_snapdir_rename2, |
444 | #else | |
ebe7e575 | 445 | .rename = zpl_snapdir_rename, |
b8d9e264 | 446 | #endif |
ebe7e575 BB |
447 | .rmdir = zpl_snapdir_rmdir, |
448 | .mkdir = zpl_snapdir_mkdir, | |
449 | }; | |
450 | ||
ebe7e575 | 451 | static struct dentry * |
8f195a90 YS |
452 | zpl_shares_lookup(struct inode *dip, struct dentry *dentry, |
453 | unsigned int flags) | |
ebe7e575 | 454 | { |
7fad6290 | 455 | fstrans_cookie_t cookie; |
ebe7e575 BB |
456 | cred_t *cr = CRED(); |
457 | struct inode *ip = NULL; | |
458 | int error; | |
459 | ||
460 | crhold(cr); | |
7fad6290 | 461 | cookie = spl_fstrans_mark(); |
ebe7e575 BB |
462 | error = -zfsctl_shares_lookup(dip, dname(dentry), &ip, |
463 | 0, cr, NULL, NULL); | |
464 | ASSERT3S(error, <=, 0); | |
7fad6290 | 465 | spl_fstrans_unmark(cookie); |
ebe7e575 BB |
466 | crfree(cr); |
467 | ||
468 | if (error) { | |
469 | if (error == -ENOENT) | |
d1d7e268 | 470 | return (d_splice_alias(NULL, dentry)); |
ebe7e575 | 471 | else |
d1d7e268 | 472 | return (ERR_PTR(error)); |
ebe7e575 BB |
473 | } |
474 | ||
d1d7e268 | 475 | return (d_splice_alias(ip, dentry)); |
ebe7e575 BB |
476 | } |
477 | ||
ebe7e575 | 478 | static int |
9464b959 | 479 | zpl_shares_iterate(struct file *filp, zpl_dir_context_t *ctx) |
ebe7e575 | 480 | { |
7fad6290 | 481 | fstrans_cookie_t cookie; |
ebe7e575 | 482 | cred_t *cr = CRED(); |
0037b49e | 483 | zfsvfs_t *zfsvfs = ITOZSB(file_inode(filp)); |
ebe7e575 | 484 | znode_t *dzp; |
0f37d0c8 | 485 | int error = 0; |
ebe7e575 | 486 | |
4352edaa | 487 | ZPL_ENTER(zfsvfs); |
7fad6290 | 488 | cookie = spl_fstrans_mark(); |
ebe7e575 | 489 | |
0037b49e | 490 | if (zfsvfs->z_shares_dir == 0) { |
9464b959 | 491 | zpl_dir_emit_dots(filp, ctx); |
0f37d0c8 | 492 | goto out; |
ebe7e575 BB |
493 | } |
494 | ||
0037b49e | 495 | error = -zfs_zget(zfsvfs, zfsvfs->z_shares_dir, &dzp); |
0f37d0c8 RY |
496 | if (error) |
497 | goto out; | |
ebe7e575 BB |
498 | |
499 | crhold(cr); | |
0f37d0c8 | 500 | error = -zfs_readdir(ZTOI(dzp), ctx, cr); |
ebe7e575 BB |
501 | crfree(cr); |
502 | ||
503 | iput(ZTOI(dzp)); | |
0f37d0c8 | 504 | out: |
7fad6290 | 505 | spl_fstrans_unmark(cookie); |
4352edaa | 506 | ZPL_EXIT(zfsvfs); |
ebe7e575 BB |
507 | ASSERT3S(error, <=, 0); |
508 | ||
509 | return (error); | |
510 | } | |
511 | ||
9baaa7de | 512 | #if !defined(HAVE_VFS_ITERATE) && !defined(HAVE_VFS_ITERATE_SHARED) |
0f37d0c8 RY |
513 | static int |
514 | zpl_shares_readdir(struct file *filp, void *dirent, filldir_t filldir) | |
515 | { | |
9464b959 BB |
516 | zpl_dir_context_t ctx = |
517 | ZPL_DIR_CONTEXT_INIT(dirent, filldir, filp->f_pos); | |
0f37d0c8 RY |
518 | int error; |
519 | ||
520 | error = zpl_shares_iterate(filp, &ctx); | |
521 | filp->f_pos = ctx.pos; | |
522 | ||
523 | return (error); | |
524 | } | |
9464b959 | 525 | #endif /* !HAVE_VFS_ITERATE && !HAVE_VFS_ITERATE_SHARED */ |
0f37d0c8 | 526 | |
ebe7e575 BB |
527 | /* ARGSUSED */ |
528 | static int | |
e2a82961 CK |
529 | #ifdef HAVE_USERNS_IOPS_GETATTR |
530 | zpl_shares_getattr_impl(struct user_namespace *user_ns, | |
531 | const struct path *path, struct kstat *stat, u32 request_mask, | |
532 | unsigned int query_flags) | |
533 | #else | |
a3478c07 OF |
534 | zpl_shares_getattr_impl(const struct path *path, struct kstat *stat, |
535 | u32 request_mask, unsigned int query_flags) | |
e2a82961 | 536 | #endif |
ebe7e575 | 537 | { |
a3478c07 | 538 | struct inode *ip = path->dentry->d_inode; |
0037b49e | 539 | zfsvfs_t *zfsvfs = ITOZSB(ip); |
ebe7e575 BB |
540 | znode_t *dzp; |
541 | int error; | |
542 | ||
4352edaa | 543 | ZPL_ENTER(zfsvfs); |
ebe7e575 | 544 | |
0037b49e | 545 | if (zfsvfs->z_shares_dir == 0) { |
e2a82961 CK |
546 | #if defined(HAVE_GENERIC_FILLATTR_USERNS) && defined(HAVE_USERNS_IOPS_GETATTR) |
547 | generic_fillattr(user_ns, path->dentry->d_inode, stat); | |
548 | #else | |
a3478c07 | 549 | generic_fillattr(path->dentry->d_inode, stat); |
e2a82961 | 550 | #endif |
ebe7e575 | 551 | stat->nlink = stat->size = 2; |
2946a1a1 | 552 | stat->atime = current_time(ip); |
4352edaa | 553 | ZPL_EXIT(zfsvfs); |
a3478c07 | 554 | return (0); |
ebe7e575 BB |
555 | } |
556 | ||
0037b49e | 557 | error = -zfs_zget(zfsvfs, zfsvfs->z_shares_dir, &dzp); |
90ee9ed3 | 558 | if (error == 0) { |
e2a82961 CK |
559 | #if defined(HAVE_GENERIC_FILLATTR_USERNS) && defined(HAVE_USERNS_IOPS_GETATTR) |
560 | error = -zfs_getattr_fast(user_ns, ZTOI(dzp), stat); | |
561 | #else | |
562 | error = -zfs_getattr_fast(kcred->user_ns, ZTOI(dzp), stat); | |
563 | #endif | |
90ee9ed3 BB |
564 | iput(ZTOI(dzp)); |
565 | } | |
ebe7e575 | 566 | |
4352edaa | 567 | ZPL_EXIT(zfsvfs); |
ebe7e575 BB |
568 | ASSERT3S(error, <=, 0); |
569 | ||
570 | return (error); | |
571 | } | |
a3478c07 | 572 | ZPL_GETATTR_WRAPPER(zpl_shares_getattr); |
ebe7e575 BB |
573 | |
574 | /* | |
575 | * The '.zfs/shares' directory file operations. | |
576 | */ | |
577 | const struct file_operations zpl_fops_shares = { | |
578 | .open = zpl_common_open, | |
579 | .llseek = generic_file_llseek, | |
580 | .read = generic_read_dir, | |
9baaa7de CC |
581 | #ifdef HAVE_VFS_ITERATE_SHARED |
582 | .iterate_shared = zpl_shares_iterate, | |
583 | #elif defined(HAVE_VFS_ITERATE) | |
0f37d0c8 RY |
584 | .iterate = zpl_shares_iterate, |
585 | #else | |
ebe7e575 | 586 | .readdir = zpl_shares_readdir, |
0f37d0c8 RY |
587 | #endif |
588 | ||
ebe7e575 BB |
589 | }; |
590 | ||
591 | /* | |
592 | * The '.zfs/shares' directory inode operations. | |
593 | */ | |
594 | const struct inode_operations zpl_ops_shares = { | |
595 | .lookup = zpl_shares_lookup, | |
596 | .getattr = zpl_shares_getattr, | |
597 | }; |