xref: /titanic_52/usr/src/uts/common/fs/zut/zut.c (revision fd9ee8b58485b20072eeef1310a88ff348d5e7fa)
1e802abbdSTim Haley /*
2e802abbdSTim Haley  * CDDL HEADER START
3e802abbdSTim Haley  *
4e802abbdSTim Haley  * The contents of this file are subject to the terms of the
5e802abbdSTim Haley  * Common Development and Distribution License (the "License").
6e802abbdSTim Haley  * You may not use this file except in compliance with the License.
7e802abbdSTim Haley  *
8e802abbdSTim Haley  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9e802abbdSTim Haley  * or http://www.opensolaris.org/os/licensing.
10e802abbdSTim Haley  * See the License for the specific language governing permissions
11e802abbdSTim Haley  * and limitations under the License.
12e802abbdSTim Haley  *
13e802abbdSTim Haley  * When distributing Covered Code, include this CDDL HEADER in each
14e802abbdSTim Haley  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15e802abbdSTim Haley  * If applicable, add the following below this CDDL HEADER, with the
16e802abbdSTim Haley  * fields enclosed by brackets "[]" replaced with your own identifying
17e802abbdSTim Haley  * information: Portions Copyright [yyyy] [name of copyright owner]
18e802abbdSTim Haley  *
19e802abbdSTim Haley  * CDDL HEADER END
20e802abbdSTim Haley  */
21e802abbdSTim Haley /*
22*fd9ee8b5Sjoyce mcintosh  * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
23e802abbdSTim Haley  */
24e802abbdSTim Haley 
25e802abbdSTim Haley #include <sys/conf.h>
26e802abbdSTim Haley #include <sys/stat.h>
27e802abbdSTim Haley #include <sys/file.h>
28e802abbdSTim Haley #include <sys/types.h>
29e802abbdSTim Haley #include <sys/pathname.h>
30e802abbdSTim Haley #include <sys/proc.h>
31e802abbdSTim Haley #include <sys/mode.h>
32e802abbdSTim Haley #include <sys/vnode.h>
33e802abbdSTim Haley #include <sys/ddi.h>
34e802abbdSTim Haley #include <sys/sunddi.h>
35e802abbdSTim Haley #include <sys/sunldi.h>
36e802abbdSTim Haley #include <sys/uio.h>
37e802abbdSTim Haley #include <sys/attr.h>
38e802abbdSTim Haley #include <sys/acl.h>
39e802abbdSTim Haley #include <sys/fs/zut.h>
40e802abbdSTim Haley 
41e802abbdSTim Haley ldi_ident_t zut_li = NULL;
42e802abbdSTim Haley dev_info_t *zut_dip;
43e802abbdSTim Haley 
44e802abbdSTim Haley static int
45e802abbdSTim Haley zut_open_dir(char *path, vnode_t *startvp, cred_t *cr, int flags,
46e802abbdSTim Haley     pathname_t *realpn, vnode_t **dvn)
47e802abbdSTim Haley {
48e802abbdSTim Haley 	pathname_t pn;
49e802abbdSTim Haley 	vnode_t *vp;
50e802abbdSTim Haley 	vnode_t *rootvp;
51e802abbdSTim Haley 	proc_t *p = curproc;
52e802abbdSTim Haley 	int error;
53e802abbdSTim Haley 
54e802abbdSTim Haley 	pn_alloc(&pn);
55e802abbdSTim Haley 	(void) strlcpy(pn.pn_buf, path, MAXPATHLEN);
56e802abbdSTim Haley 	pn.pn_pathlen = strlen(path);
57e802abbdSTim Haley 
58e802abbdSTim Haley 	mutex_enter(&p->p_lock);	/* for u_rdir and u_cdir */
59e802abbdSTim Haley 	if ((rootvp = PTOU(p)->u_rdir) == NULL)
60e802abbdSTim Haley 		rootvp = rootdir;
61e802abbdSTim Haley 	else if (rootvp != rootdir)	/* no need to VN_HOLD rootdir */
62e802abbdSTim Haley 		VN_HOLD(rootvp);
63e802abbdSTim Haley 
64e802abbdSTim Haley 	if (pn.pn_path[0] == '/') {
65e802abbdSTim Haley 		vp = rootvp;
66e802abbdSTim Haley 	} else {
67e802abbdSTim Haley 		vp = (startvp == NULL) ? PTOU(p)->u_cdir : startvp;
68e802abbdSTim Haley 	}
69e802abbdSTim Haley 	VN_HOLD(vp);
70e802abbdSTim Haley 	mutex_exit(&p->p_lock);
71e802abbdSTim Haley 
72e802abbdSTim Haley 	/*
73e802abbdSTim Haley 	 * Skip over leading slashes
74e802abbdSTim Haley 	 */
75e802abbdSTim Haley 	while (pn.pn_path[0] == '/') {
76e802abbdSTim Haley 		pn.pn_path++;
77e802abbdSTim Haley 		pn.pn_pathlen--;
78e802abbdSTim Haley 	}
79e802abbdSTim Haley 
80e802abbdSTim Haley 	error = lookuppnvp(&pn, realpn, flags | FOLLOW, NULL,
81e802abbdSTim Haley 	    dvn, rootvp, vp, cr);
82e802abbdSTim Haley 
83e802abbdSTim Haley 	/*
84e802abbdSTim Haley 	 * If we lack read access to the directory, we should error out.
85e802abbdSTim Haley 	 */
86e802abbdSTim Haley 	if (!error) {
87e802abbdSTim Haley 		if (vfs_has_feature((*dvn)->v_vfsp, VFSFT_ACEMASKONACCESS)) {
88e802abbdSTim Haley 			error = VOP_ACCESS(*dvn, ACE_LIST_DIRECTORY,
89e802abbdSTim Haley 			    V_ACE_MASK, cr, NULL);
90e802abbdSTim Haley 		} else {
91e802abbdSTim Haley 			error = VOP_ACCESS(*dvn, VREAD, 0, cr, NULL);
92e802abbdSTim Haley 		}
93e802abbdSTim Haley 	}
94e802abbdSTim Haley 
95e802abbdSTim Haley 	pn_free(&pn);
96e802abbdSTim Haley 
97e802abbdSTim Haley 	return (error);
98e802abbdSTim Haley }
99e802abbdSTim Haley 
100e802abbdSTim Haley static int
101e802abbdSTim Haley zut_readdir(intptr_t arg, cred_t *cr, int iflag, int *rvalp)
102e802abbdSTim Haley {
103e802abbdSTim Haley 	zut_readdir_t *zr;
104e802abbdSTim Haley 	struct iovec aiov;
105e802abbdSTim Haley 	struct uio auio;
106e802abbdSTim Haley 	vnode_t *dvn = NULL;
107e802abbdSTim Haley 	vnode_t *fvn = NULL;
108e802abbdSTim Haley 	char *kbuf;
109e802abbdSTim Haley 	int flags = 0;
110e802abbdSTim Haley 	int error, rc;
111e802abbdSTim Haley 
112e802abbdSTim Haley 	zr = kmem_zalloc(sizeof (zut_readdir_t), KM_SLEEP);
113e802abbdSTim Haley 	error = ddi_copyin((void *)arg, zr, sizeof (zut_readdir_t), iflag);
114e802abbdSTim Haley 	if (error)
115e802abbdSTim Haley 		goto zutr_bail;
116e802abbdSTim Haley 
117e802abbdSTim Haley 	kbuf = kmem_zalloc(zr->zr_buflen, KM_SLEEP);
118e802abbdSTim Haley 
119e802abbdSTim Haley 	zr->zr_retcode = zut_open_dir(zr->zr_dir, NULL, cr, flags, NULL, &dvn);
120e802abbdSTim Haley 	if (zr->zr_retcode)
121e802abbdSTim Haley 		goto zutr_done;
122e802abbdSTim Haley 
123e802abbdSTim Haley 	if (zr->zr_reqflags & ZUT_XATTR) {
124e802abbdSTim Haley 		vattr_t vattr;
125e802abbdSTim Haley 
126e802abbdSTim Haley 		zr->zr_retcode = VOP_LOOKUP(dvn, zr->zr_file, &fvn,
127e802abbdSTim Haley 		    NULL, flags, NULL, cr, NULL, NULL, NULL);
128e802abbdSTim Haley 		VN_RELE(dvn);
129e802abbdSTim Haley 		dvn = NULL;
130e802abbdSTim Haley 		if (zr->zr_retcode)
131e802abbdSTim Haley 			goto zutr_done;
132e802abbdSTim Haley 
133e802abbdSTim Haley 		/*
134e802abbdSTim Haley 		 * In order to access hidden attribute directory the
135e802abbdSTim Haley 		 * user must have appropriate read access and be able
136e802abbdSTim Haley 		 * to stat() the file
137e802abbdSTim Haley 		 */
138e802abbdSTim Haley 		if (vfs_has_feature(fvn->v_vfsp, VFSFT_ACEMASKONACCESS)) {
139e802abbdSTim Haley 			zr->zr_retcode = VOP_ACCESS(fvn, ACE_READ_NAMED_ATTRS,
140e802abbdSTim Haley 			    V_ACE_MASK, cr, NULL);
141e802abbdSTim Haley 		} else {
142e802abbdSTim Haley 			zr->zr_retcode = VOP_ACCESS(fvn, VREAD, 0, cr, NULL);
143e802abbdSTim Haley 		}
144e802abbdSTim Haley 		if (zr->zr_retcode)
145e802abbdSTim Haley 			goto zutr_done;
146e802abbdSTim Haley 
147e802abbdSTim Haley 		vattr.va_mask = AT_ALL;
148e802abbdSTim Haley 		zr->zr_retcode = VOP_GETATTR(fvn, &vattr, 0, cr, NULL);
149e802abbdSTim Haley 		if (zr->zr_retcode)
150e802abbdSTim Haley 			goto zutr_done;
151e802abbdSTim Haley 
152e802abbdSTim Haley 		zr->zr_retcode = VOP_LOOKUP(fvn, "", &dvn, NULL,
153e802abbdSTim Haley 		    flags | LOOKUP_XATTR, NULL, cr, NULL, NULL, NULL);
154e802abbdSTim Haley 		VN_RELE(fvn);
155e802abbdSTim Haley 		if (zr->zr_retcode)
156e802abbdSTim Haley 			goto zutr_done;
157e802abbdSTim Haley 	}
158e802abbdSTim Haley 
159e802abbdSTim Haley 	aiov.iov_base = kbuf;
160e802abbdSTim Haley 	aiov.iov_len = zr->zr_buflen;
161e802abbdSTim Haley 	auio.uio_iov = &aiov;
162e802abbdSTim Haley 	auio.uio_iovcnt = 1;
163e802abbdSTim Haley 	auio.uio_loffset = zr->zr_loffset;
164e802abbdSTim Haley 	auio.uio_segflg = UIO_SYSSPACE;
165e802abbdSTim Haley 	auio.uio_resid = zr->zr_buflen;
166e802abbdSTim Haley 	auio.uio_fmode = 0;
167e802abbdSTim Haley 	auio.uio_extflg = UIO_COPY_CACHED;
168e802abbdSTim Haley 
169e802abbdSTim Haley 	if (zr->zr_reqflags & ZUT_EXTRDDIR)
170e802abbdSTim Haley 		flags |= V_RDDIR_ENTFLAGS;
171e802abbdSTim Haley 	if (zr->zr_reqflags & ZUT_ACCFILTER)
172e802abbdSTim Haley 		flags |= V_RDDIR_ACCFILTER;
173e802abbdSTim Haley 
174e802abbdSTim Haley 	(void) VOP_RWLOCK(dvn, V_WRITELOCK_FALSE, NULL);
175e802abbdSTim Haley 	zr->zr_retcode = VOP_READDIR(dvn, &auio, cr, &zr->zr_eof,
176e802abbdSTim Haley 	    NULL, flags);
177e802abbdSTim Haley 	VOP_RWUNLOCK(dvn, V_WRITELOCK_FALSE, NULL);
178e802abbdSTim Haley 	VN_RELE(dvn);
179e802abbdSTim Haley 
180e802abbdSTim Haley 	zr->zr_bytes = aiov.iov_base - kbuf;
181e802abbdSTim Haley 	zr->zr_loffset = auio.uio_loffset;
182e802abbdSTim Haley 
183e802abbdSTim Haley 	error = ddi_copyout(kbuf, (void *)(uintptr_t)zr->zr_buf,
184e802abbdSTim Haley 	    zr->zr_buflen, iflag);
185e802abbdSTim Haley 
186e802abbdSTim Haley zutr_done:
187e802abbdSTim Haley 	kmem_free(kbuf, zr->zr_buflen);
188e802abbdSTim Haley 	rc = ddi_copyout(zr, (void *)arg, sizeof (zut_readdir_t), iflag);
189e802abbdSTim Haley 	if (error == 0)
190e802abbdSTim Haley 		error = rc;
191e802abbdSTim Haley 
192e802abbdSTim Haley zutr_bail:
193e802abbdSTim Haley 	kmem_free(zr, sizeof (zut_readdir_t));
194e802abbdSTim Haley 	if (rvalp)
195e802abbdSTim Haley 		*rvalp = error;
196e802abbdSTim Haley 	return (error);
197e802abbdSTim Haley }
198e802abbdSTim Haley 
199e802abbdSTim Haley static int
200e802abbdSTim Haley zut_stat64(vnode_t *vp, struct stat64 *sb, uint64_t *xvs, int flag, cred_t *cr)
201e802abbdSTim Haley {
202e802abbdSTim Haley 	xoptattr_t *xoap = NULL;
203e802abbdSTim Haley 	xvattr_t xv = { 0 };
204e802abbdSTim Haley 	int error;
205e802abbdSTim Haley 
206e802abbdSTim Haley 	xva_init(&xv);
207e802abbdSTim Haley 
208e802abbdSTim Haley 	XVA_SET_REQ(&xv, XAT_ARCHIVE);
209e802abbdSTim Haley 	XVA_SET_REQ(&xv, XAT_SYSTEM);
210e802abbdSTim Haley 	XVA_SET_REQ(&xv, XAT_READONLY);
211e802abbdSTim Haley 	XVA_SET_REQ(&xv, XAT_HIDDEN);
212e802abbdSTim Haley 	XVA_SET_REQ(&xv, XAT_NOUNLINK);
213e802abbdSTim Haley 	XVA_SET_REQ(&xv, XAT_IMMUTABLE);
214e802abbdSTim Haley 	XVA_SET_REQ(&xv, XAT_APPENDONLY);
215e802abbdSTim Haley 	XVA_SET_REQ(&xv, XAT_NODUMP);
216e802abbdSTim Haley 	XVA_SET_REQ(&xv, XAT_OPAQUE);
217e802abbdSTim Haley 	XVA_SET_REQ(&xv, XAT_AV_QUARANTINED);
218e802abbdSTim Haley 	XVA_SET_REQ(&xv, XAT_AV_MODIFIED);
2197a286c47SDai Ngo 	XVA_SET_REQ(&xv, XAT_REPARSE);
220*fd9ee8b5Sjoyce mcintosh 	XVA_SET_REQ(&xv, XAT_OFFLINE);
221*fd9ee8b5Sjoyce mcintosh 	XVA_SET_REQ(&xv, XAT_SPARSE);
222e802abbdSTim Haley 
223e802abbdSTim Haley 	xv.xva_vattr.va_mask |= AT_STAT | AT_NBLOCKS | AT_BLKSIZE | AT_SIZE;
224e802abbdSTim Haley 	if (error = VOP_GETATTR(vp, &xv.xva_vattr, flag, cr, NULL))
225e802abbdSTim Haley 		return (error);
226e802abbdSTim Haley 
227e802abbdSTim Haley 	bzero(sb, sizeof (sb));
228e802abbdSTim Haley 	sb->st_dev = xv.xva_vattr.va_fsid;
229e802abbdSTim Haley 	sb->st_ino = xv.xva_vattr.va_nodeid;
230e802abbdSTim Haley 	sb->st_mode = VTTOIF(xv.xva_vattr.va_type) | xv.xva_vattr.va_mode;
231e802abbdSTim Haley 	sb->st_nlink = xv.xva_vattr.va_nlink;
232e802abbdSTim Haley 	sb->st_uid = xv.xva_vattr.va_uid;
233e802abbdSTim Haley 	sb->st_gid = xv.xva_vattr.va_gid;
234e802abbdSTim Haley 	sb->st_rdev = xv.xva_vattr.va_rdev;
235e802abbdSTim Haley 	sb->st_size = xv.xva_vattr.va_size;
236e802abbdSTim Haley 	sb->st_atim = xv.xva_vattr.va_atime;
237e802abbdSTim Haley 	sb->st_mtim = xv.xva_vattr.va_mtime;
238e802abbdSTim Haley 	sb->st_ctim = xv.xva_vattr.va_ctime;
239e802abbdSTim Haley 	sb->st_blksize = xv.xva_vattr.va_blksize;
240e802abbdSTim Haley 	sb->st_blocks = xv.xva_vattr.va_nblocks;
241e802abbdSTim Haley 	sb->st_fstype[0] = 0;
242e802abbdSTim Haley 
243e802abbdSTim Haley 	if ((xoap = xva_getxoptattr(&xv)) == NULL)
244e802abbdSTim Haley 		return (0);
245e802abbdSTim Haley 
246e802abbdSTim Haley 	if (XVA_ISSET_RTN(&xv, XAT_ARCHIVE) && xoap->xoa_archive)
247e802abbdSTim Haley 		*xvs |= (1 << F_ARCHIVE);
248e802abbdSTim Haley 	if (XVA_ISSET_RTN(&xv, XAT_SYSTEM) && xoap->xoa_system)
249e802abbdSTim Haley 		*xvs |= (1 << F_SYSTEM);
250e802abbdSTim Haley 	if (XVA_ISSET_RTN(&xv, XAT_READONLY) && xoap->xoa_readonly)
251e802abbdSTim Haley 		*xvs |= (1 << F_READONLY);
252e802abbdSTim Haley 	if (XVA_ISSET_RTN(&xv, XAT_HIDDEN) && xoap->xoa_hidden)
253e802abbdSTim Haley 		*xvs |= (1 << F_HIDDEN);
254e802abbdSTim Haley 	if (XVA_ISSET_RTN(&xv, XAT_NOUNLINK) && xoap->xoa_nounlink)
255e802abbdSTim Haley 		*xvs |= (1 << F_NOUNLINK);
256e802abbdSTim Haley 	if (XVA_ISSET_RTN(&xv, XAT_IMMUTABLE) && xoap->xoa_immutable)
257e802abbdSTim Haley 		*xvs |= (1 << F_IMMUTABLE);
258e802abbdSTim Haley 	if (XVA_ISSET_RTN(&xv, XAT_APPENDONLY) && xoap->xoa_appendonly)
259e802abbdSTim Haley 		*xvs |= (1 << F_APPENDONLY);
260e802abbdSTim Haley 	if (XVA_ISSET_RTN(&xv, XAT_NODUMP) && xoap->xoa_nodump)
261e802abbdSTim Haley 		*xvs |= (1 << F_NODUMP);
262e802abbdSTim Haley 	if (XVA_ISSET_RTN(&xv, XAT_OPAQUE) && xoap->xoa_opaque)
263e802abbdSTim Haley 		*xvs |= (1 << F_OPAQUE);
264e802abbdSTim Haley 	if (XVA_ISSET_RTN(&xv, XAT_AV_QUARANTINED) && xoap->xoa_av_quarantined)
265e802abbdSTim Haley 		*xvs |= (1 << F_AV_QUARANTINED);
266e802abbdSTim Haley 	if (XVA_ISSET_RTN(&xv, XAT_AV_MODIFIED) && xoap->xoa_av_modified)
267e802abbdSTim Haley 		*xvs |= (1 << F_AV_MODIFIED);
2687a286c47SDai Ngo 	if (XVA_ISSET_RTN(&xv, XAT_REPARSE) && xoap->xoa_reparse)
2697a286c47SDai Ngo 		*xvs |= (1 << F_REPARSE);
270*fd9ee8b5Sjoyce mcintosh 	if (XVA_ISSET_RTN(&xv, XAT_OFFLINE) && xoap->xoa_offline)
271*fd9ee8b5Sjoyce mcintosh 		*xvs |= (1 << F_OFFLINE);
272*fd9ee8b5Sjoyce mcintosh 	if (XVA_ISSET_RTN(&xv, XAT_SPARSE) && xoap->xoa_sparse)
273*fd9ee8b5Sjoyce mcintosh 		*xvs |= (1 << F_SPARSE);
274e802abbdSTim Haley 
275e802abbdSTim Haley 	return (0);
276e802abbdSTim Haley }
277e802abbdSTim Haley 
278e802abbdSTim Haley /*ARGSUSED*/
279e802abbdSTim Haley static int
280e802abbdSTim Haley zut_lookup(intptr_t arg, cred_t *cr, int iflag, int *rvalp)
281e802abbdSTim Haley {
282e802abbdSTim Haley 	zut_lookup_t *zl;
283e802abbdSTim Haley 	pathname_t rpn;
284e802abbdSTim Haley 	vnode_t *dvn = NULL;
285e802abbdSTim Haley 	vnode_t *fvn = NULL;
286e802abbdSTim Haley 	vnode_t *xdvn = NULL;
287e802abbdSTim Haley 	vnode_t *xfvn = NULL;
288e802abbdSTim Haley 	vnode_t *release = NULL;
289e802abbdSTim Haley 	int flags = 0;
290e802abbdSTim Haley 	int error, rc;
291e802abbdSTim Haley 
292e802abbdSTim Haley 	zl = kmem_zalloc(sizeof (zut_lookup_t), KM_SLEEP);
293e802abbdSTim Haley 
294e802abbdSTim Haley 	error = ddi_copyin((void *)arg, zl, sizeof (zut_lookup_t), iflag);
295e802abbdSTim Haley 	if (error)
296e802abbdSTim Haley 		goto zutl_bail;
297e802abbdSTim Haley 
298e802abbdSTim Haley 	pn_alloc(&rpn);
299e802abbdSTim Haley 	bzero(rpn.pn_buf, MAXPATHLEN);
300e802abbdSTim Haley 
301e802abbdSTim Haley 	zl->zl_retcode = zut_open_dir(zl->zl_dir, NULL, cr, flags, &rpn, &dvn);
302e802abbdSTim Haley 	if (zl->zl_retcode)
303e802abbdSTim Haley 		goto zutl_done;
304e802abbdSTim Haley 
305e802abbdSTim Haley 	if (zl->zl_reqflags & ZUT_IGNORECASE)
306e802abbdSTim Haley 		flags |= FIGNORECASE;
307e802abbdSTim Haley 
308e802abbdSTim Haley 	zl->zl_retcode = VOP_LOOKUP(dvn, zl->zl_file, &fvn, NULL, flags, NULL,
309e802abbdSTim Haley 	    cr, NULL, &zl->zl_deflags, &rpn);
310e802abbdSTim Haley 	if (zl->zl_retcode)
311e802abbdSTim Haley 		goto zutl_done;
312e802abbdSTim Haley 
313e802abbdSTim Haley 	release = fvn;
314e802abbdSTim Haley 
315e802abbdSTim Haley 	if (zl->zl_reqflags & ZUT_XATTR) {
316e802abbdSTim Haley 		vattr_t vattr;
317e802abbdSTim Haley 
318e802abbdSTim Haley 		/*
319e802abbdSTim Haley 		 * In order to access hidden attribute directory the
320e802abbdSTim Haley 		 * user must have appropriate read access and be able
321e802abbdSTim Haley 		 * to stat() the file
322e802abbdSTim Haley 		 */
323e802abbdSTim Haley 		if (vfs_has_feature(fvn->v_vfsp, VFSFT_ACEMASKONACCESS)) {
324e802abbdSTim Haley 			zl->zl_retcode = VOP_ACCESS(fvn, ACE_READ_NAMED_ATTRS,
325e802abbdSTim Haley 			    V_ACE_MASK, cr, NULL);
326e802abbdSTim Haley 		} else {
327e802abbdSTim Haley 			zl->zl_retcode = VOP_ACCESS(fvn, VREAD, 0, cr, NULL);
328e802abbdSTim Haley 		}
329e802abbdSTim Haley 		if (zl->zl_retcode)
330e802abbdSTim Haley 			goto zutl_done;
331e802abbdSTim Haley 
332e802abbdSTim Haley 		vattr.va_mask = AT_ALL;
333e802abbdSTim Haley 		zl->zl_retcode = VOP_GETATTR(fvn, &vattr, 0, cr, NULL);
334e802abbdSTim Haley 		if (zl->zl_retcode)
335e802abbdSTim Haley 			goto zutl_done;
336e802abbdSTim Haley 
337e802abbdSTim Haley 		zl->zl_retcode = VOP_LOOKUP(fvn, "", &xdvn, NULL,
338e802abbdSTim Haley 		    flags | LOOKUP_XATTR, NULL, cr, NULL, NULL, NULL);
339e802abbdSTim Haley 		if (zl->zl_retcode)
340e802abbdSTim Haley 			goto zutl_done;
341e802abbdSTim Haley 		VN_RELE(fvn);
342e802abbdSTim Haley 		release = xdvn;
343e802abbdSTim Haley 
344e802abbdSTim Haley 		zl->zl_retcode = VOP_LOOKUP(xdvn, zl->zl_xfile, &xfvn,
345e802abbdSTim Haley 		    NULL, flags, NULL, cr, NULL, &zl->zl_deflags, &rpn);
346e802abbdSTim Haley 		if (zl->zl_retcode)
347e802abbdSTim Haley 			goto zutl_done;
348e802abbdSTim Haley 		VN_RELE(xdvn);
349e802abbdSTim Haley 		release = xfvn;
350e802abbdSTim Haley 	}
351e802abbdSTim Haley 
352e802abbdSTim Haley 	if (zl->zl_reqflags & ZUT_GETSTAT) {
353e802abbdSTim Haley 		zl->zl_retcode = zut_stat64(release,
354e802abbdSTim Haley 		    &zl->zl_statbuf, &zl->zl_xvattrs, 0, cr);
355e802abbdSTim Haley 	}
356e802abbdSTim Haley 
357e802abbdSTim Haley zutl_done:
358e802abbdSTim Haley 	(void) strlcpy(zl->zl_real, rpn.pn_path, MAXPATHLEN);
359e802abbdSTim Haley 
360e802abbdSTim Haley 	rc = ddi_copyout(zl, (void *)arg, sizeof (zut_lookup_t), iflag);
361e802abbdSTim Haley 	if (error == 0)
362e802abbdSTim Haley 		error = rc;
363e802abbdSTim Haley 
364e802abbdSTim Haley 	if (release)
365e802abbdSTim Haley 		VN_RELE(release);
366e802abbdSTim Haley 	if (dvn)
367e802abbdSTim Haley 		VN_RELE(dvn);
368e802abbdSTim Haley 	pn_free(&rpn);
369e802abbdSTim Haley 
370e802abbdSTim Haley zutl_bail:
371e802abbdSTim Haley 	kmem_free(zl, sizeof (zut_lookup_t));
372e802abbdSTim Haley 	if (rvalp)
373e802abbdSTim Haley 		*rvalp = error;
374e802abbdSTim Haley 	return (error);
375e802abbdSTim Haley }
376e802abbdSTim Haley 
377e802abbdSTim Haley /*ARGSUSED*/
378e802abbdSTim Haley static int
379e802abbdSTim Haley zut_ioctl(dev_t dev, int cmd, intptr_t arg, int flag, cred_t *cr, int *rvalp)
380e802abbdSTim Haley {
381e802abbdSTim Haley 	int error;
382e802abbdSTim Haley 
383e802abbdSTim Haley 	if (getminor(dev) != 0)
384e802abbdSTim Haley 		return (ENXIO);
385e802abbdSTim Haley 
386e802abbdSTim Haley 	if (cmd <= ZUT_IOC_MIN_CMD || cmd >= ZUT_IOC_MAX_CMD)
387e802abbdSTim Haley 		return (EINVAL);
388e802abbdSTim Haley 
389e802abbdSTim Haley 	switch (cmd) {
390e802abbdSTim Haley 	case ZUT_IOC_LOOKUP:
391e802abbdSTim Haley 		error = zut_lookup(arg, cr, flag, rvalp);
392e802abbdSTim Haley 		break;
393e802abbdSTim Haley 	case ZUT_IOC_READDIR:
394e802abbdSTim Haley 		error = zut_readdir(arg, cr, flag, rvalp);
395e802abbdSTim Haley 	default:
396e802abbdSTim Haley 		break;
397e802abbdSTim Haley 	}
398e802abbdSTim Haley 
399e802abbdSTim Haley 	return (error);
400e802abbdSTim Haley }
401e802abbdSTim Haley 
402e802abbdSTim Haley static int
403e802abbdSTim Haley zut_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
404e802abbdSTim Haley {
405e802abbdSTim Haley 	if (cmd != DDI_ATTACH)
406e802abbdSTim Haley 		return (DDI_FAILURE);
407e802abbdSTim Haley 
408e802abbdSTim Haley 	if (ddi_create_minor_node(dip, "zut", S_IFCHR, 0,
409e802abbdSTim Haley 	    DDI_PSEUDO, 0) == DDI_FAILURE)
410e802abbdSTim Haley 		return (DDI_FAILURE);
411e802abbdSTim Haley 
412e802abbdSTim Haley 	zut_dip = dip;
413e802abbdSTim Haley 
414e802abbdSTim Haley 	ddi_report_dev(dip);
415e802abbdSTim Haley 
416e802abbdSTim Haley 	return (DDI_SUCCESS);
417e802abbdSTim Haley }
418e802abbdSTim Haley 
419e802abbdSTim Haley static int
420e802abbdSTim Haley zut_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
421e802abbdSTim Haley {
422e802abbdSTim Haley 	if (cmd != DDI_DETACH)
423e802abbdSTim Haley 		return (DDI_FAILURE);
424e802abbdSTim Haley 
425e802abbdSTim Haley 	zut_dip = NULL;
426e802abbdSTim Haley 
427e802abbdSTim Haley 	ddi_prop_remove_all(dip);
428e802abbdSTim Haley 	ddi_remove_minor_node(dip, NULL);
429e802abbdSTim Haley 
430e802abbdSTim Haley 	return (DDI_SUCCESS);
431e802abbdSTim Haley }
432e802abbdSTim Haley 
433e802abbdSTim Haley /*ARGSUSED*/
434e802abbdSTim Haley static int
435e802abbdSTim Haley zut_info(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, void **result)
436e802abbdSTim Haley {
437e802abbdSTim Haley 	switch (infocmd) {
438e802abbdSTim Haley 	case DDI_INFO_DEVT2DEVINFO:
439e802abbdSTim Haley 		*result = zut_dip;
440e802abbdSTim Haley 		return (DDI_SUCCESS);
441e802abbdSTim Haley 
442e802abbdSTim Haley 	case DDI_INFO_DEVT2INSTANCE:
443e802abbdSTim Haley 		*result = (void *)0;
444e802abbdSTim Haley 		return (DDI_SUCCESS);
445e802abbdSTim Haley 	}
446e802abbdSTim Haley 
447e802abbdSTim Haley 	return (DDI_FAILURE);
448e802abbdSTim Haley }
449e802abbdSTim Haley 
450e802abbdSTim Haley /*ARGSUSED*/
451e802abbdSTim Haley int
452e802abbdSTim Haley zut_open(dev_t *devp, int flag, int otyp, cred_t *cr)
453e802abbdSTim Haley {
454e802abbdSTim Haley 	minor_t minor = getminor(*devp);
455e802abbdSTim Haley 
456e802abbdSTim Haley 	if (minor == 0)			/* This is the control device */
457e802abbdSTim Haley 		return (0);
458e802abbdSTim Haley 
459e802abbdSTim Haley 	return (ENXIO);
460e802abbdSTim Haley }
461e802abbdSTim Haley 
462e802abbdSTim Haley /*ARGSUSED*/
463e802abbdSTim Haley int
464e802abbdSTim Haley zut_close(dev_t dev, int flag, int otyp, cred_t *cr)
465e802abbdSTim Haley {
466e802abbdSTim Haley 	minor_t minor = getminor(dev);
467e802abbdSTim Haley 
468e802abbdSTim Haley 	if (minor == 0)		/* This is the control device */
469e802abbdSTim Haley 		return (0);
470e802abbdSTim Haley 
471e802abbdSTim Haley 	return (ENXIO);
472e802abbdSTim Haley }
473e802abbdSTim Haley 
474e802abbdSTim Haley /*
475e802abbdSTim Haley  * /dev/zut is the control node, i.e. minor 0.
476e802abbdSTim Haley  *
477e802abbdSTim Haley  * There are no other minor nodes, and /dev/zut basically does nothing
478e802abbdSTim Haley  * other than serve up ioctls.
479e802abbdSTim Haley  */
480e802abbdSTim Haley static struct cb_ops zut_cb_ops = {
481e802abbdSTim Haley 	zut_open,	/* open */
482e802abbdSTim Haley 	zut_close,	/* close */
483e802abbdSTim Haley 	nodev,		/* strategy */
484e802abbdSTim Haley 	nodev,		/* print */
485e802abbdSTim Haley 	nodev,		/* dump */
486e802abbdSTim Haley 	nodev,		/* read */
487e802abbdSTim Haley 	nodev,		/* write */
488e802abbdSTim Haley 	zut_ioctl,	/* ioctl */
489e802abbdSTim Haley 	nodev,		/* devmap */
490e802abbdSTim Haley 	nodev,		/* mmap */
491e802abbdSTim Haley 	nodev,		/* segmap */
492e802abbdSTim Haley 	nochpoll,	/* poll */
493e802abbdSTim Haley 	ddi_prop_op,	/* prop_op */
494e802abbdSTim Haley 	NULL,		/* streamtab */
495e802abbdSTim Haley 	D_NEW | D_MP | D_64BIT,		/* Driver compatibility flag */
496e802abbdSTim Haley 	CB_REV,		/* version */
497e802abbdSTim Haley 	nodev,		/* async read */
498e802abbdSTim Haley 	nodev,		/* async write */
499e802abbdSTim Haley };
500e802abbdSTim Haley 
501e802abbdSTim Haley static struct dev_ops zut_dev_ops = {
502e802abbdSTim Haley 	DEVO_REV,	/* version */
503e802abbdSTim Haley 	0,		/* refcnt */
504e802abbdSTim Haley 	zut_info,	/* info */
505e802abbdSTim Haley 	nulldev,	/* identify */
506e802abbdSTim Haley 	nulldev,	/* probe */
507e802abbdSTim Haley 	zut_attach,	/* attach */
508e802abbdSTim Haley 	zut_detach,	/* detach */
509e802abbdSTim Haley 	nodev,		/* reset */
510e802abbdSTim Haley 	&zut_cb_ops,	/* driver operations */
511e802abbdSTim Haley 	NULL		/* no bus operations */
512e802abbdSTim Haley };
513e802abbdSTim Haley 
514e802abbdSTim Haley static struct modldrv zut_modldrv = {
515e802abbdSTim Haley 	&mod_driverops, "ZFS unit test " ZUT_VERSION_STRING,
516e802abbdSTim Haley 	    &zut_dev_ops
517e802abbdSTim Haley };
518e802abbdSTim Haley 
519e802abbdSTim Haley static struct modlinkage modlinkage = {
520e802abbdSTim Haley 	MODREV_1,
521e802abbdSTim Haley 	(void *)&zut_modldrv,
522e802abbdSTim Haley 	NULL
523e802abbdSTim Haley };
524e802abbdSTim Haley 
525e802abbdSTim Haley int
526e802abbdSTim Haley _init(void)
527e802abbdSTim Haley {
528e802abbdSTim Haley 	int error;
529e802abbdSTim Haley 
530e802abbdSTim Haley 	if ((error = mod_install(&modlinkage)) != 0) {
531e802abbdSTim Haley 		return (error);
532e802abbdSTim Haley 	}
533e802abbdSTim Haley 
534e802abbdSTim Haley 	error = ldi_ident_from_mod(&modlinkage, &zut_li);
535e802abbdSTim Haley 	ASSERT(error == 0);
536e802abbdSTim Haley 
537e802abbdSTim Haley 	return (0);
538e802abbdSTim Haley }
539e802abbdSTim Haley 
540e802abbdSTim Haley int
541e802abbdSTim Haley _fini(void)
542e802abbdSTim Haley {
543e802abbdSTim Haley 	int error;
544e802abbdSTim Haley 
545e802abbdSTim Haley 	if ((error = mod_remove(&modlinkage)) != 0)
546e802abbdSTim Haley 		return (error);
547e802abbdSTim Haley 
548e802abbdSTim Haley 	ldi_ident_release(zut_li);
549e802abbdSTim Haley 	zut_li = NULL;
550e802abbdSTim Haley 
551e802abbdSTim Haley 	return (error);
552e802abbdSTim Haley }
553e802abbdSTim Haley 
554e802abbdSTim Haley int
555e802abbdSTim Haley _info(struct modinfo *modinfop)
556e802abbdSTim Haley {
557e802abbdSTim Haley 	return (mod_info(&modlinkage, modinfop));
558e802abbdSTim Haley }
559