Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/sys/contrib/openzfs/module/os/linux/zfs/zpl_ctldir.c
48775 views
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 Lawrence Livermore National Security, LLC.
24
* Produced at Lawrence Livermore National Laboratory (cf, DISCLAIMER).
25
* LLNL-CODE-403049.
26
* Rewritten for Linux by:
27
* Rohan Puri <[email protected]>
28
* Brian Behlendorf <[email protected]>
29
*/
30
31
#include <sys/zfs_znode.h>
32
#include <sys/zfs_vfsops.h>
33
#include <sys/zfs_vnops.h>
34
#include <sys/zfs_ctldir.h>
35
#include <sys/zpl.h>
36
#include <sys/dmu.h>
37
#include <sys/dsl_dataset.h>
38
#include <sys/zap.h>
39
40
/*
41
* Common open routine. Disallow any write access.
42
*/
43
static int
44
zpl_common_open(struct inode *ip, struct file *filp)
45
{
46
if (blk_mode_is_open_write(filp->f_mode))
47
return (-EACCES);
48
49
return (generic_file_open(ip, filp));
50
}
51
52
/*
53
* Get root directory contents.
54
*/
55
static int
56
zpl_root_iterate(struct file *filp, struct dir_context *ctx)
57
{
58
zfsvfs_t *zfsvfs = ITOZSB(file_inode(filp));
59
int error = 0;
60
61
if (zfsvfs->z_show_ctldir == ZFS_SNAPDIR_DISABLED) {
62
return (SET_ERROR(ENOENT));
63
}
64
65
if ((error = zpl_enter(zfsvfs, FTAG)) != 0)
66
return (error);
67
68
if (!dir_emit_dots(filp, ctx))
69
goto out;
70
71
if (ctx->pos == 2) {
72
if (!dir_emit(ctx, ZFS_SNAPDIR_NAME,
73
strlen(ZFS_SNAPDIR_NAME), ZFSCTL_INO_SNAPDIR, DT_DIR))
74
goto out;
75
76
ctx->pos++;
77
}
78
79
if (ctx->pos == 3) {
80
if (!dir_emit(ctx, ZFS_SHAREDIR_NAME,
81
strlen(ZFS_SHAREDIR_NAME), ZFSCTL_INO_SHARES, DT_DIR))
82
goto out;
83
84
ctx->pos++;
85
}
86
out:
87
zpl_exit(zfsvfs, FTAG);
88
89
return (error);
90
}
91
92
/*
93
* Get root directory attributes.
94
*/
95
static int
96
#ifdef HAVE_IDMAP_IOPS_GETATTR
97
zpl_root_getattr_impl(struct mnt_idmap *user_ns,
98
const struct path *path, struct kstat *stat, u32 request_mask,
99
unsigned int query_flags)
100
#elif defined(HAVE_USERNS_IOPS_GETATTR)
101
zpl_root_getattr_impl(struct user_namespace *user_ns,
102
const struct path *path, struct kstat *stat, u32 request_mask,
103
unsigned int query_flags)
104
#else
105
zpl_root_getattr_impl(const struct path *path, struct kstat *stat,
106
u32 request_mask, unsigned int query_flags)
107
#endif
108
{
109
(void) request_mask, (void) query_flags;
110
struct inode *ip = path->dentry->d_inode;
111
112
#if (defined(HAVE_USERNS_IOPS_GETATTR) || defined(HAVE_IDMAP_IOPS_GETATTR))
113
#ifdef HAVE_GENERIC_FILLATTR_USERNS
114
generic_fillattr(user_ns, ip, stat);
115
#elif defined(HAVE_GENERIC_FILLATTR_IDMAP)
116
generic_fillattr(user_ns, ip, stat);
117
#elif defined(HAVE_GENERIC_FILLATTR_IDMAP_REQMASK)
118
generic_fillattr(user_ns, request_mask, ip, stat);
119
#else
120
(void) user_ns;
121
#endif
122
#else
123
generic_fillattr(ip, stat);
124
#endif
125
stat->atime = current_time(ip);
126
127
return (0);
128
}
129
ZPL_GETATTR_WRAPPER(zpl_root_getattr);
130
131
static struct dentry *
132
zpl_root_lookup(struct inode *dip, struct dentry *dentry, unsigned int flags)
133
{
134
cred_t *cr = CRED();
135
struct inode *ip;
136
int error;
137
138
crhold(cr);
139
error = -zfsctl_root_lookup(dip, dname(dentry), &ip, 0, cr, NULL, NULL);
140
ASSERT3S(error, <=, 0);
141
crfree(cr);
142
143
if (error) {
144
if (error == -ENOENT)
145
return (d_splice_alias(NULL, dentry));
146
else
147
return (ERR_PTR(error));
148
}
149
150
return (d_splice_alias(ip, dentry));
151
}
152
153
/*
154
* The '.zfs' control directory file and inode operations.
155
*/
156
const struct file_operations zpl_fops_root = {
157
.open = zpl_common_open,
158
.llseek = generic_file_llseek,
159
.read = generic_read_dir,
160
.iterate_shared = zpl_root_iterate,
161
};
162
163
const struct inode_operations zpl_ops_root = {
164
.lookup = zpl_root_lookup,
165
.getattr = zpl_root_getattr,
166
};
167
168
static struct vfsmount *
169
zpl_snapdir_automount(struct path *path)
170
{
171
int error;
172
173
error = -zfsctl_snapshot_mount(path, 0);
174
if (error)
175
return (ERR_PTR(error));
176
177
/*
178
* Rather than returning the new vfsmount for the snapshot we must
179
* return NULL to indicate a mount collision. This is done because
180
* the user space mount calls do_add_mount() which adds the vfsmount
181
* to the name space. If we returned the new mount here it would be
182
* added again to the vfsmount list resulting in list corruption.
183
*/
184
return (NULL);
185
}
186
187
/*
188
* Negative dentries must always be revalidated so newly created snapshots
189
* can be detected and automounted. Normal dentries should be kept because
190
* as of the 3.18 kernel revaliding the mountpoint dentry will result in
191
* the snapshot being immediately unmounted.
192
*/
193
#ifdef HAVE_D_REVALIDATE_4ARGS
194
static int
195
zpl_snapdir_revalidate(struct inode *dir, const struct qstr *name,
196
struct dentry *dentry, unsigned int flags)
197
#else
198
static int
199
zpl_snapdir_revalidate(struct dentry *dentry, unsigned int flags)
200
#endif
201
{
202
return (!!dentry->d_inode);
203
}
204
205
static const struct dentry_operations zpl_dops_snapdirs = {
206
/*
207
* Auto mounting of snapshots is only supported for 2.6.37 and
208
* newer kernels. Prior to this kernel the ops->follow_link()
209
* callback was used as a hack to trigger the mount. The
210
* resulting vfsmount was then explicitly grafted in to the
211
* name space. While it might be possible to add compatibility
212
* code to accomplish this it would require considerable care.
213
*/
214
.d_automount = zpl_snapdir_automount,
215
.d_revalidate = zpl_snapdir_revalidate,
216
};
217
218
/*
219
* For the .zfs control directory to work properly we must be able to override
220
* the default operations table and register custom .d_automount and
221
* .d_revalidate callbacks.
222
*/
223
static void
224
set_snapdir_dentry_ops(struct dentry *dentry, unsigned int extraflags) {
225
static const unsigned int op_flags =
226
DCACHE_OP_HASH | DCACHE_OP_COMPARE |
227
DCACHE_OP_REVALIDATE | DCACHE_OP_DELETE |
228
DCACHE_OP_PRUNE | DCACHE_OP_WEAK_REVALIDATE | DCACHE_OP_REAL;
229
230
#ifdef HAVE_D_SET_D_OP
231
/*
232
* d_set_d_op() will set the DCACHE_OP_ flags according to what it
233
* finds in the passed dentry_operations, so we don't have to.
234
*
235
* We clear the flags and the old op table before calling d_set_d_op()
236
* because issues a warning when the dentry operations table is already
237
* set.
238
*/
239
dentry->d_op = NULL;
240
dentry->d_flags &= ~op_flags;
241
d_set_d_op(dentry, &zpl_dops_snapdirs);
242
dentry->d_flags |= extraflags;
243
#else
244
/*
245
* Since 6.17 there's no exported way to modify dentry ops, so we have
246
* to reach in and do it ourselves. This should be safe for our very
247
* narrow use case, which is to create or splice in an entry to give
248
* access to a snapshot.
249
*
250
* We need to set the op flags directly. We hardcode
251
* DCACHE_OP_REVALIDATE because that's the only operation we have; if
252
* we ever extend zpl_dops_snapdirs we will need to update the op flags
253
* to match.
254
*/
255
spin_lock(&dentry->d_lock);
256
dentry->d_op = &zpl_dops_snapdirs;
257
dentry->d_flags &= ~op_flags;
258
dentry->d_flags |= DCACHE_OP_REVALIDATE | extraflags;
259
spin_unlock(&dentry->d_lock);
260
#endif
261
}
262
263
static struct dentry *
264
zpl_snapdir_lookup(struct inode *dip, struct dentry *dentry,
265
unsigned int flags)
266
{
267
fstrans_cookie_t cookie;
268
cred_t *cr = CRED();
269
struct inode *ip = NULL;
270
int error;
271
272
crhold(cr);
273
cookie = spl_fstrans_mark();
274
error = -zfsctl_snapdir_lookup(dip, dname(dentry), &ip,
275
0, cr, NULL, NULL);
276
ASSERT3S(error, <=, 0);
277
spl_fstrans_unmark(cookie);
278
crfree(cr);
279
280
if (error && error != -ENOENT)
281
return (ERR_PTR(error));
282
283
ASSERT(error == 0 || ip == NULL);
284
set_snapdir_dentry_ops(dentry, DCACHE_NEED_AUTOMOUNT);
285
return (d_splice_alias(ip, dentry));
286
}
287
288
static int
289
zpl_snapdir_iterate(struct file *filp, struct dir_context *ctx)
290
{
291
zfsvfs_t *zfsvfs = ITOZSB(file_inode(filp));
292
fstrans_cookie_t cookie;
293
char snapname[MAXNAMELEN];
294
boolean_t case_conflict;
295
uint64_t id, pos;
296
int error = 0;
297
298
if ((error = zpl_enter(zfsvfs, FTAG)) != 0)
299
return (error);
300
cookie = spl_fstrans_mark();
301
302
if (!dir_emit_dots(filp, ctx))
303
goto out;
304
305
/* Start the position at 0 if it already emitted . and .. */
306
pos = (ctx->pos == 2 ? 0 : ctx->pos);
307
while (error == 0) {
308
dsl_pool_config_enter(dmu_objset_pool(zfsvfs->z_os), FTAG);
309
error = -dmu_snapshot_list_next(zfsvfs->z_os, MAXNAMELEN,
310
snapname, &id, &pos, &case_conflict);
311
dsl_pool_config_exit(dmu_objset_pool(zfsvfs->z_os), FTAG);
312
if (error)
313
goto out;
314
315
if (!dir_emit(ctx, snapname, strlen(snapname),
316
ZFSCTL_INO_SHARES - id, DT_DIR))
317
goto out;
318
319
ctx->pos = pos;
320
}
321
out:
322
spl_fstrans_unmark(cookie);
323
zpl_exit(zfsvfs, FTAG);
324
325
if (error == -ENOENT)
326
return (0);
327
328
return (error);
329
}
330
331
static int
332
#ifdef HAVE_IOPS_RENAME_USERNS
333
zpl_snapdir_rename2(struct user_namespace *user_ns, struct inode *sdip,
334
struct dentry *sdentry, struct inode *tdip, struct dentry *tdentry,
335
unsigned int flags)
336
#elif defined(HAVE_IOPS_RENAME_IDMAP)
337
zpl_snapdir_rename2(struct mnt_idmap *user_ns, struct inode *sdip,
338
struct dentry *sdentry, struct inode *tdip, struct dentry *tdentry,
339
unsigned int flags)
340
#else
341
zpl_snapdir_rename2(struct inode *sdip, struct dentry *sdentry,
342
struct inode *tdip, struct dentry *tdentry, unsigned int flags)
343
#endif
344
{
345
cred_t *cr = CRED();
346
int error;
347
348
/* We probably don't want to support renameat2(2) in ctldir */
349
if (flags)
350
return (-EINVAL);
351
352
crhold(cr);
353
error = -zfsctl_snapdir_rename(sdip, dname(sdentry),
354
tdip, dname(tdentry), cr, 0);
355
ASSERT3S(error, <=, 0);
356
crfree(cr);
357
358
return (error);
359
}
360
361
#if (!defined(HAVE_RENAME_WANTS_FLAGS) && \
362
!defined(HAVE_IOPS_RENAME_USERNS) && \
363
!defined(HAVE_IOPS_RENAME_IDMAP))
364
static int
365
zpl_snapdir_rename(struct inode *sdip, struct dentry *sdentry,
366
struct inode *tdip, struct dentry *tdentry)
367
{
368
return (zpl_snapdir_rename2(sdip, sdentry, tdip, tdentry, 0));
369
}
370
#endif
371
372
static int
373
zpl_snapdir_rmdir(struct inode *dip, struct dentry *dentry)
374
{
375
cred_t *cr = CRED();
376
int error;
377
378
crhold(cr);
379
error = -zfsctl_snapdir_remove(dip, dname(dentry), cr, 0);
380
ASSERT3S(error, <=, 0);
381
crfree(cr);
382
383
return (error);
384
}
385
386
#if defined(HAVE_IOPS_MKDIR_USERNS)
387
static int
388
zpl_snapdir_mkdir(struct user_namespace *user_ns, struct inode *dip,
389
struct dentry *dentry, umode_t mode)
390
#elif defined(HAVE_IOPS_MKDIR_IDMAP)
391
static int
392
zpl_snapdir_mkdir(struct mnt_idmap *user_ns, struct inode *dip,
393
struct dentry *dentry, umode_t mode)
394
#elif defined(HAVE_IOPS_MKDIR_DENTRY)
395
static struct dentry *
396
zpl_snapdir_mkdir(struct mnt_idmap *user_ns, struct inode *dip,
397
struct dentry *dentry, umode_t mode)
398
#else
399
static int
400
zpl_snapdir_mkdir(struct inode *dip, struct dentry *dentry, umode_t mode)
401
#endif
402
{
403
cred_t *cr = CRED();
404
vattr_t *vap;
405
struct inode *ip;
406
int error;
407
408
crhold(cr);
409
vap = kmem_zalloc(sizeof (vattr_t), KM_SLEEP);
410
#if (defined(HAVE_IOPS_MKDIR_USERNS) || defined(HAVE_IOPS_MKDIR_IDMAP))
411
zpl_vap_init(vap, dip, mode | S_IFDIR, cr, user_ns);
412
#else
413
zpl_vap_init(vap, dip, mode | S_IFDIR, cr, zfs_init_idmap);
414
#endif
415
416
error = -zfsctl_snapdir_mkdir(dip, dname(dentry), vap, &ip, cr, 0);
417
if (error == 0) {
418
set_snapdir_dentry_ops(dentry, 0);
419
d_instantiate(dentry, ip);
420
}
421
422
kmem_free(vap, sizeof (vattr_t));
423
ASSERT3S(error, <=, 0);
424
crfree(cr);
425
426
#if defined(HAVE_IOPS_MKDIR_DENTRY)
427
return (ERR_PTR(error));
428
#else
429
return (error);
430
#endif
431
}
432
433
/*
434
* Get snapshot directory attributes.
435
*/
436
static int
437
#ifdef HAVE_IDMAP_IOPS_GETATTR
438
zpl_snapdir_getattr_impl(struct mnt_idmap *user_ns,
439
const struct path *path, struct kstat *stat, u32 request_mask,
440
unsigned int query_flags)
441
#elif defined(HAVE_USERNS_IOPS_GETATTR)
442
zpl_snapdir_getattr_impl(struct user_namespace *user_ns,
443
const struct path *path, struct kstat *stat, u32 request_mask,
444
unsigned int query_flags)
445
#else
446
zpl_snapdir_getattr_impl(const struct path *path, struct kstat *stat,
447
u32 request_mask, unsigned int query_flags)
448
#endif
449
{
450
(void) request_mask, (void) query_flags;
451
struct inode *ip = path->dentry->d_inode;
452
zfsvfs_t *zfsvfs = ITOZSB(ip);
453
int error;
454
455
if ((error = zpl_enter(zfsvfs, FTAG)) != 0)
456
return (error);
457
#if (defined(HAVE_USERNS_IOPS_GETATTR) || defined(HAVE_IDMAP_IOPS_GETATTR))
458
#ifdef HAVE_GENERIC_FILLATTR_USERNS
459
generic_fillattr(user_ns, ip, stat);
460
#elif defined(HAVE_GENERIC_FILLATTR_IDMAP)
461
generic_fillattr(user_ns, ip, stat);
462
#elif defined(HAVE_GENERIC_FILLATTR_IDMAP_REQMASK)
463
generic_fillattr(user_ns, request_mask, ip, stat);
464
#else
465
(void) user_ns;
466
#endif
467
#else
468
generic_fillattr(ip, stat);
469
#endif
470
471
stat->nlink = stat->size = 2;
472
473
dsl_dataset_t *ds = dmu_objset_ds(zfsvfs->z_os);
474
if (dsl_dataset_phys(ds)->ds_snapnames_zapobj != 0) {
475
uint64_t snap_count;
476
int err = zap_count(
477
dmu_objset_pool(ds->ds_objset)->dp_meta_objset,
478
dsl_dataset_phys(ds)->ds_snapnames_zapobj, &snap_count);
479
if (err != 0) {
480
zpl_exit(zfsvfs, FTAG);
481
return (-err);
482
}
483
stat->nlink += snap_count;
484
}
485
486
stat->ctime = stat->mtime = dmu_objset_snap_cmtime(zfsvfs->z_os);
487
stat->atime = current_time(ip);
488
zpl_exit(zfsvfs, FTAG);
489
490
return (0);
491
}
492
ZPL_GETATTR_WRAPPER(zpl_snapdir_getattr);
493
494
/*
495
* The '.zfs/snapshot' directory file operations. These mainly control
496
* generating the list of available snapshots when doing an 'ls' in the
497
* directory. See zpl_snapdir_readdir().
498
*/
499
const struct file_operations zpl_fops_snapdir = {
500
.open = zpl_common_open,
501
.llseek = generic_file_llseek,
502
.read = generic_read_dir,
503
.iterate_shared = zpl_snapdir_iterate,
504
505
};
506
507
/*
508
* The '.zfs/snapshot' directory inode operations. These mainly control
509
* creating an inode for a snapshot directory and initializing the needed
510
* infrastructure to automount the snapshot. See zpl_snapdir_lookup().
511
*/
512
const struct inode_operations zpl_ops_snapdir = {
513
.lookup = zpl_snapdir_lookup,
514
.getattr = zpl_snapdir_getattr,
515
#if (defined(HAVE_RENAME_WANTS_FLAGS) || \
516
defined(HAVE_IOPS_RENAME_USERNS) || \
517
defined(HAVE_IOPS_RENAME_IDMAP))
518
.rename = zpl_snapdir_rename2,
519
#else
520
.rename = zpl_snapdir_rename,
521
#endif
522
.rmdir = zpl_snapdir_rmdir,
523
.mkdir = zpl_snapdir_mkdir,
524
};
525
526
static struct dentry *
527
zpl_shares_lookup(struct inode *dip, struct dentry *dentry,
528
unsigned int flags)
529
{
530
fstrans_cookie_t cookie;
531
cred_t *cr = CRED();
532
struct inode *ip = NULL;
533
int error;
534
535
crhold(cr);
536
cookie = spl_fstrans_mark();
537
error = -zfsctl_shares_lookup(dip, dname(dentry), &ip,
538
0, cr, NULL, NULL);
539
ASSERT3S(error, <=, 0);
540
spl_fstrans_unmark(cookie);
541
crfree(cr);
542
543
if (error) {
544
if (error == -ENOENT)
545
return (d_splice_alias(NULL, dentry));
546
else
547
return (ERR_PTR(error));
548
}
549
550
return (d_splice_alias(ip, dentry));
551
}
552
553
static int
554
zpl_shares_iterate(struct file *filp, struct dir_context *ctx)
555
{
556
fstrans_cookie_t cookie;
557
cred_t *cr = CRED();
558
zfsvfs_t *zfsvfs = ITOZSB(file_inode(filp));
559
znode_t *dzp;
560
int error = 0;
561
562
if ((error = zpl_enter(zfsvfs, FTAG)) != 0)
563
return (error);
564
cookie = spl_fstrans_mark();
565
566
if (zfsvfs->z_shares_dir == 0) {
567
dir_emit_dots(filp, ctx);
568
goto out;
569
}
570
571
error = -zfs_zget(zfsvfs, zfsvfs->z_shares_dir, &dzp);
572
if (error)
573
goto out;
574
575
crhold(cr);
576
error = -zfs_readdir(ZTOI(dzp), ctx, cr);
577
crfree(cr);
578
579
iput(ZTOI(dzp));
580
out:
581
spl_fstrans_unmark(cookie);
582
zpl_exit(zfsvfs, FTAG);
583
ASSERT3S(error, <=, 0);
584
585
return (error);
586
}
587
588
static int
589
#ifdef HAVE_USERNS_IOPS_GETATTR
590
zpl_shares_getattr_impl(struct user_namespace *user_ns,
591
const struct path *path, struct kstat *stat, u32 request_mask,
592
unsigned int query_flags)
593
#elif defined(HAVE_IDMAP_IOPS_GETATTR)
594
zpl_shares_getattr_impl(struct mnt_idmap *user_ns,
595
const struct path *path, struct kstat *stat, u32 request_mask,
596
unsigned int query_flags)
597
#else
598
zpl_shares_getattr_impl(const struct path *path, struct kstat *stat,
599
u32 request_mask, unsigned int query_flags)
600
#endif
601
{
602
(void) request_mask, (void) query_flags;
603
struct inode *ip = path->dentry->d_inode;
604
zfsvfs_t *zfsvfs = ITOZSB(ip);
605
znode_t *dzp;
606
int error;
607
608
if ((error = zpl_enter(zfsvfs, FTAG)) != 0)
609
return (error);
610
611
if (zfsvfs->z_shares_dir == 0) {
612
#if (defined(HAVE_USERNS_IOPS_GETATTR) || defined(HAVE_IDMAP_IOPS_GETATTR))
613
#ifdef HAVE_GENERIC_FILLATTR_USERNS
614
generic_fillattr(user_ns, path->dentry->d_inode, stat);
615
#elif defined(HAVE_GENERIC_FILLATTR_IDMAP)
616
generic_fillattr(user_ns, path->dentry->d_inode, stat);
617
#elif defined(HAVE_GENERIC_FILLATTR_IDMAP_REQMASK)
618
generic_fillattr(user_ns, request_mask, ip, stat);
619
#else
620
(void) user_ns;
621
#endif
622
#else
623
generic_fillattr(path->dentry->d_inode, stat);
624
#endif
625
stat->nlink = stat->size = 2;
626
stat->atime = current_time(ip);
627
zpl_exit(zfsvfs, FTAG);
628
return (0);
629
}
630
631
error = -zfs_zget(zfsvfs, zfsvfs->z_shares_dir, &dzp);
632
if (error == 0) {
633
#ifdef HAVE_GENERIC_FILLATTR_IDMAP_REQMASK
634
error = -zfs_getattr_fast(user_ns, request_mask, ZTOI(dzp),
635
stat);
636
#elif (defined(HAVE_USERNS_IOPS_GETATTR) || defined(HAVE_IDMAP_IOPS_GETATTR))
637
error = -zfs_getattr_fast(user_ns, ZTOI(dzp), stat);
638
#else
639
error = -zfs_getattr_fast(kcred->user_ns, ZTOI(dzp), stat);
640
#endif
641
iput(ZTOI(dzp));
642
}
643
644
zpl_exit(zfsvfs, FTAG);
645
ASSERT3S(error, <=, 0);
646
647
return (error);
648
}
649
ZPL_GETATTR_WRAPPER(zpl_shares_getattr);
650
651
/*
652
* The '.zfs/shares' directory file operations.
653
*/
654
const struct file_operations zpl_fops_shares = {
655
.open = zpl_common_open,
656
.llseek = generic_file_llseek,
657
.read = generic_read_dir,
658
.iterate_shared = zpl_shares_iterate,
659
};
660
661
/*
662
* The '.zfs/shares' directory inode operations.
663
*/
664
const struct inode_operations zpl_ops_shares = {
665
.lookup = zpl_shares_lookup,
666
.getattr = zpl_shares_getattr,
667
};
668
669