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.
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.
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]
22 * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
28 #include <sys/types.h>
29 #include <sys/pathname.h>
32 #include <sys/vnode.h>
34 #include <sys/sunddi.h>
35 #include <sys/sunldi.h>
39 #include <sys/fs/zut.h>
41 ldi_ident_t zut_li
= NULL
;
45 zut_open_dir(char *path
, vnode_t
*startvp
, cred_t
*cr
, int flags
,
46 pathname_t
*realpn
, vnode_t
**dvn
)
55 (void) strlcpy(pn
.pn_buf
, path
, MAXPATHLEN
);
56 pn
.pn_pathlen
= strlen(path
);
58 mutex_enter(&p
->p_lock
); /* for u_rdir and u_cdir */
59 if ((rootvp
= PTOU(p
)->u_rdir
) == NULL
)
61 else if (rootvp
!= rootdir
) /* no need to VN_HOLD rootdir */
64 if (pn
.pn_path
[0] == '/') {
67 vp
= (startvp
== NULL
) ? PTOU(p
)->u_cdir
: startvp
;
70 mutex_exit(&p
->p_lock
);
73 * Skip over leading slashes
75 while (pn
.pn_path
[0] == '/') {
80 error
= lookuppnvp(&pn
, realpn
, flags
| FOLLOW
, NULL
,
84 * If we lack read access to the directory, we should error out.
87 if (vfs_has_feature((*dvn
)->v_vfsp
, VFSFT_ACEMASKONACCESS
)) {
88 error
= fop_access(*dvn
, ACE_LIST_DIRECTORY
,
89 V_ACE_MASK
, cr
, NULL
);
91 error
= fop_access(*dvn
, VREAD
, 0, cr
, NULL
);
101 zut_readdir(intptr_t arg
, cred_t
*cr
, int iflag
, int *rvalp
)
112 zr
= kmem_zalloc(sizeof (zut_readdir_t
), KM_SLEEP
);
113 error
= ddi_copyin((void *)arg
, zr
, sizeof (zut_readdir_t
), iflag
);
117 kbuf
= kmem_zalloc(zr
->zr_buflen
, KM_SLEEP
);
119 zr
->zr_retcode
= zut_open_dir(zr
->zr_dir
, NULL
, cr
, flags
, NULL
, &dvn
);
123 if (zr
->zr_reqflags
& ZUT_XATTR
) {
126 zr
->zr_retcode
= fop_lookup(dvn
, zr
->zr_file
, &fvn
,
127 NULL
, flags
, NULL
, cr
, NULL
, NULL
, NULL
);
134 * In order to access hidden attribute directory the
135 * user must have appropriate read access and be able
138 if (vfs_has_feature(fvn
->v_vfsp
, VFSFT_ACEMASKONACCESS
)) {
139 zr
->zr_retcode
= fop_access(fvn
, ACE_READ_NAMED_ATTRS
,
140 V_ACE_MASK
, cr
, NULL
);
142 zr
->zr_retcode
= fop_access(fvn
, VREAD
, 0, cr
, NULL
);
147 vattr
.va_mask
= VATTR_ALL
;
148 zr
->zr_retcode
= fop_getattr(fvn
, &vattr
, 0, cr
, NULL
);
152 zr
->zr_retcode
= fop_lookup(fvn
, "", &dvn
, NULL
,
153 flags
| LOOKUP_XATTR
, NULL
, cr
, NULL
, NULL
, NULL
);
159 aiov
.iov_base
= kbuf
;
160 aiov
.iov_len
= zr
->zr_buflen
;
161 auio
.uio_iov
= &aiov
;
163 auio
.uio_loffset
= zr
->zr_loffset
;
164 auio
.uio_segflg
= UIO_SYSSPACE
;
165 auio
.uio_resid
= zr
->zr_buflen
;
167 auio
.uio_extflg
= UIO_COPY_CACHED
;
169 if (zr
->zr_reqflags
& ZUT_EXTRDDIR
)
170 flags
|= V_RDDIR_ENTFLAGS
;
171 if (zr
->zr_reqflags
& ZUT_ACCFILTER
)
172 flags
|= V_RDDIR_ACCFILTER
;
174 (void) fop_rwlock(dvn
, V_WRITELOCK_FALSE
, NULL
);
175 zr
->zr_retcode
= fop_readdir(dvn
, &auio
, cr
, &zr
->zr_eof
,
177 fop_rwunlock(dvn
, V_WRITELOCK_FALSE
, NULL
);
180 zr
->zr_bytes
= aiov
.iov_base
- kbuf
;
181 zr
->zr_loffset
= auio
.uio_loffset
;
183 error
= ddi_copyout(kbuf
, (void *)(uintptr_t)zr
->zr_buf
,
184 zr
->zr_buflen
, iflag
);
187 kmem_free(kbuf
, zr
->zr_buflen
);
188 rc
= ddi_copyout(zr
, (void *)arg
, sizeof (zut_readdir_t
), iflag
);
193 kmem_free(zr
, sizeof (zut_readdir_t
));
200 zut_stat64(vnode_t
*vp
, struct stat
*sb
, uint64_t *xvs
, int flag
, cred_t
*cr
)
202 xoptattr_t
*xoap
= NULL
;
208 XVA_SET_REQ(&xv
, XAT_ARCHIVE
);
209 XVA_SET_REQ(&xv
, XAT_SYSTEM
);
210 XVA_SET_REQ(&xv
, XAT_READONLY
);
211 XVA_SET_REQ(&xv
, XAT_HIDDEN
);
212 XVA_SET_REQ(&xv
, XAT_NOUNLINK
);
213 XVA_SET_REQ(&xv
, XAT_IMMUTABLE
);
214 XVA_SET_REQ(&xv
, XAT_APPENDONLY
);
215 XVA_SET_REQ(&xv
, XAT_NODUMP
);
216 XVA_SET_REQ(&xv
, XAT_OPAQUE
);
217 XVA_SET_REQ(&xv
, XAT_AV_QUARANTINED
);
218 XVA_SET_REQ(&xv
, XAT_AV_MODIFIED
);
219 XVA_SET_REQ(&xv
, XAT_REPARSE
);
220 XVA_SET_REQ(&xv
, XAT_OFFLINE
);
221 XVA_SET_REQ(&xv
, XAT_SPARSE
);
223 xv
.xva_vattr
.va_mask
|= VATTR_STAT
| VATTR_NBLOCKS
| VATTR_BLKSIZE
| VATTR_SIZE
;
224 if (error
= fop_getattr(vp
, &xv
.xva_vattr
, flag
, cr
, NULL
))
227 bzero(sb
, sizeof (sb
));
228 sb
->st_dev
= xv
.xva_vattr
.va_fsid
;
229 sb
->st_ino
= xv
.xva_vattr
.va_nodeid
;
230 sb
->st_mode
= VTTOIF(xv
.xva_vattr
.va_type
) | xv
.xva_vattr
.va_mode
;
231 sb
->st_nlink
= xv
.xva_vattr
.va_nlink
;
232 sb
->st_uid
= xv
.xva_vattr
.va_uid
;
233 sb
->st_gid
= xv
.xva_vattr
.va_gid
;
234 sb
->st_rdev
= xv
.xva_vattr
.va_rdev
;
235 sb
->st_size
= xv
.xva_vattr
.va_size
;
236 sb
->st_atim
= xv
.xva_vattr
.va_atime
;
237 sb
->st_mtim
= xv
.xva_vattr
.va_mtime
;
238 sb
->st_ctim
= xv
.xva_vattr
.va_ctime
;
239 sb
->st_blksize
= xv
.xva_vattr
.va_blksize
;
240 sb
->st_blocks
= xv
.xva_vattr
.va_nblocks
;
241 sb
->st_fstype
[0] = 0;
243 if ((xoap
= xva_getxoptattr(&xv
)) == NULL
)
246 if (XVA_ISSET_RTN(&xv
, XAT_ARCHIVE
) && xoap
->xoa_archive
)
247 *xvs
|= (1 << F_ARCHIVE
);
248 if (XVA_ISSET_RTN(&xv
, XAT_SYSTEM
) && xoap
->xoa_system
)
249 *xvs
|= (1 << F_SYSTEM
);
250 if (XVA_ISSET_RTN(&xv
, XAT_READONLY
) && xoap
->xoa_readonly
)
251 *xvs
|= (1 << F_READONLY
);
252 if (XVA_ISSET_RTN(&xv
, XAT_HIDDEN
) && xoap
->xoa_hidden
)
253 *xvs
|= (1 << F_HIDDEN
);
254 if (XVA_ISSET_RTN(&xv
, XAT_NOUNLINK
) && xoap
->xoa_nounlink
)
255 *xvs
|= (1 << F_NOUNLINK
);
256 if (XVA_ISSET_RTN(&xv
, XAT_IMMUTABLE
) && xoap
->xoa_immutable
)
257 *xvs
|= (1 << F_IMMUTABLE
);
258 if (XVA_ISSET_RTN(&xv
, XAT_APPENDONLY
) && xoap
->xoa_appendonly
)
259 *xvs
|= (1 << F_APPENDONLY
);
260 if (XVA_ISSET_RTN(&xv
, XAT_NODUMP
) && xoap
->xoa_nodump
)
261 *xvs
|= (1 << F_NODUMP
);
262 if (XVA_ISSET_RTN(&xv
, XAT_OPAQUE
) && xoap
->xoa_opaque
)
263 *xvs
|= (1 << F_OPAQUE
);
264 if (XVA_ISSET_RTN(&xv
, XAT_AV_QUARANTINED
) && xoap
->xoa_av_quarantined
)
265 *xvs
|= (1 << F_AV_QUARANTINED
);
266 if (XVA_ISSET_RTN(&xv
, XAT_AV_MODIFIED
) && xoap
->xoa_av_modified
)
267 *xvs
|= (1 << F_AV_MODIFIED
);
268 if (XVA_ISSET_RTN(&xv
, XAT_REPARSE
) && xoap
->xoa_reparse
)
269 *xvs
|= (1 << F_REPARSE
);
270 if (XVA_ISSET_RTN(&xv
, XAT_OFFLINE
) && xoap
->xoa_offline
)
271 *xvs
|= (1 << F_OFFLINE
);
272 if (XVA_ISSET_RTN(&xv
, XAT_SPARSE
) && xoap
->xoa_sparse
)
273 *xvs
|= (1 << F_SPARSE
);
280 zut_lookup(intptr_t arg
, cred_t
*cr
, int iflag
, int *rvalp
)
286 vnode_t
*xdvn
= NULL
;
287 vnode_t
*xfvn
= NULL
;
288 vnode_t
*release
= NULL
;
292 zl
= kmem_zalloc(sizeof (zut_lookup_t
), KM_SLEEP
);
294 error
= ddi_copyin((void *)arg
, zl
, sizeof (zut_lookup_t
), iflag
);
299 bzero(rpn
.pn_buf
, MAXPATHLEN
);
301 zl
->zl_retcode
= zut_open_dir(zl
->zl_dir
, NULL
, cr
, flags
, &rpn
, &dvn
);
305 if (zl
->zl_reqflags
& ZUT_IGNORECASE
)
306 flags
|= FIGNORECASE
;
308 zl
->zl_retcode
= fop_lookup(dvn
, zl
->zl_file
, &fvn
, NULL
, flags
, NULL
,
309 cr
, NULL
, &zl
->zl_deflags
, &rpn
);
315 if (zl
->zl_reqflags
& ZUT_XATTR
) {
319 * In order to access hidden attribute directory the
320 * user must have appropriate read access and be able
323 if (vfs_has_feature(fvn
->v_vfsp
, VFSFT_ACEMASKONACCESS
)) {
324 zl
->zl_retcode
= fop_access(fvn
, ACE_READ_NAMED_ATTRS
,
325 V_ACE_MASK
, cr
, NULL
);
327 zl
->zl_retcode
= fop_access(fvn
, VREAD
, 0, cr
, NULL
);
332 vattr
.va_mask
= VATTR_ALL
;
333 zl
->zl_retcode
= fop_getattr(fvn
, &vattr
, 0, cr
, NULL
);
337 zl
->zl_retcode
= fop_lookup(fvn
, "", &xdvn
, NULL
,
338 flags
| LOOKUP_XATTR
, NULL
, cr
, NULL
, NULL
, NULL
);
344 zl
->zl_retcode
= fop_lookup(xdvn
, zl
->zl_xfile
, &xfvn
,
345 NULL
, flags
, NULL
, cr
, NULL
, &zl
->zl_deflags
, &rpn
);
352 if (zl
->zl_reqflags
& ZUT_GETSTAT
) {
353 zl
->zl_retcode
= zut_stat64(release
,
354 &zl
->zl_statbuf
, &zl
->zl_xvattrs
, 0, cr
);
358 (void) strlcpy(zl
->zl_real
, rpn
.pn_path
, MAXPATHLEN
);
360 rc
= ddi_copyout(zl
, (void *)arg
, sizeof (zut_lookup_t
), iflag
);
371 kmem_free(zl
, sizeof (zut_lookup_t
));
379 zut_ioctl(dev_t dev
, int cmd
, intptr_t arg
, int flag
, cred_t
*cr
, int *rvalp
)
383 if (getminor(dev
) != 0)
386 if (cmd
<= ZUT_IOC_MIN_CMD
|| cmd
>= ZUT_IOC_MAX_CMD
)
391 error
= zut_lookup(arg
, cr
, flag
, rvalp
);
393 case ZUT_IOC_READDIR
:
394 error
= zut_readdir(arg
, cr
, flag
, rvalp
);
403 zut_attach(dev_info_t
*dip
, ddi_attach_cmd_t cmd
)
405 if (cmd
!= DDI_ATTACH
)
406 return (DDI_FAILURE
);
408 if (ddi_create_minor_node(dip
, "zut", S_IFCHR
, 0,
409 DDI_PSEUDO
, 0) == DDI_FAILURE
)
410 return (DDI_FAILURE
);
416 return (DDI_SUCCESS
);
420 zut_detach(dev_info_t
*dip
, ddi_detach_cmd_t cmd
)
422 if (cmd
!= DDI_DETACH
)
423 return (DDI_FAILURE
);
427 ddi_prop_remove_all(dip
);
428 ddi_remove_minor_node(dip
, NULL
);
430 return (DDI_SUCCESS
);
435 zut_info(dev_info_t
*dip
, ddi_info_cmd_t infocmd
, void *arg
, void **result
)
438 case DDI_INFO_DEVT2DEVINFO
:
440 return (DDI_SUCCESS
);
442 case DDI_INFO_DEVT2INSTANCE
:
444 return (DDI_SUCCESS
);
447 return (DDI_FAILURE
);
452 zut_open(dev_t
*devp
, int flag
, int otyp
, cred_t
*cr
)
454 minor_t minor
= getminor(*devp
);
456 if (minor
== 0) /* This is the control device */
464 zut_close(dev_t dev
, int flag
, int otyp
, cred_t
*cr
)
466 minor_t minor
= getminor(dev
);
468 if (minor
== 0) /* This is the control device */
475 * /dev/zut is the control node, i.e. minor 0.
477 * There are no other minor nodes, and /dev/zut basically does nothing
478 * other than serve up ioctls.
480 static struct cb_ops zut_cb_ops
= {
482 zut_close
, /* close */
483 nodev
, /* strategy */
488 zut_ioctl
, /* ioctl */
493 ddi_prop_op
, /* prop_op */
494 NULL
, /* streamtab */
495 D_NEW
| D_MP
| D_64BIT
, /* Driver compatibility flag */
496 CB_REV
, /* version */
497 nodev
, /* async read */
498 nodev
, /* async write */
501 static struct dev_ops zut_dev_ops
= {
502 DEVO_REV
, /* version */
505 nulldev
, /* identify */
507 zut_attach
, /* attach */
508 zut_detach
, /* detach */
510 &zut_cb_ops
, /* driver operations */
511 NULL
/* no bus operations */
514 static struct modldrv zut_modldrv
= {
515 &mod_driverops
, "ZFS unit test " ZUT_VERSION_STRING
,
519 static struct modlinkage modlinkage
= {
521 (void *)&zut_modldrv
,
530 if ((error
= mod_install(&modlinkage
)) != 0) {
534 error
= ldi_ident_from_mod(&modlinkage
, &zut_li
);
545 if ((error
= mod_remove(&modlinkage
)) != 0)
548 ldi_ident_release(zut_li
);
555 _info(struct modinfo
*modinfop
)
557 return (mod_info(&modlinkage
, modinfop
));