xref: /freebsd/sys/fs/smbfs/smbfs_vfsops.c (revision 0430a5e2895a13bd6219cc701523388716f362e3)
1d167cf6fSWarner Losh /*-
2681a5bbeSBoris Popov  * Copyright (c) 2000-2001, Boris Popov
3681a5bbeSBoris Popov  * All rights reserved.
4681a5bbeSBoris Popov  *
5681a5bbeSBoris Popov  * Redistribution and use in source and binary forms, with or without
6681a5bbeSBoris Popov  * modification, are permitted provided that the following conditions
7681a5bbeSBoris Popov  * are met:
8681a5bbeSBoris Popov  * 1. Redistributions of source code must retain the above copyright
9681a5bbeSBoris Popov  *    notice, this list of conditions and the following disclaimer.
10681a5bbeSBoris Popov  * 2. Redistributions in binary form must reproduce the above copyright
11681a5bbeSBoris Popov  *    notice, this list of conditions and the following disclaimer in the
12681a5bbeSBoris Popov  *    documentation and/or other materials provided with the distribution.
13681a5bbeSBoris Popov  * 3. All advertising materials mentioning features or use of this software
14681a5bbeSBoris Popov  *    must display the following acknowledgement:
15681a5bbeSBoris Popov  *    This product includes software developed by Boris Popov.
16681a5bbeSBoris Popov  * 4. Neither the name of the author nor the names of any co-contributors
17681a5bbeSBoris Popov  *    may be used to endorse or promote products derived from this software
18681a5bbeSBoris Popov  *    without specific prior written permission.
19681a5bbeSBoris Popov  *
20681a5bbeSBoris Popov  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
21681a5bbeSBoris Popov  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22681a5bbeSBoris Popov  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23681a5bbeSBoris Popov  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
24681a5bbeSBoris Popov  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25681a5bbeSBoris Popov  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26681a5bbeSBoris Popov  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27681a5bbeSBoris Popov  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28681a5bbeSBoris Popov  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29681a5bbeSBoris Popov  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30681a5bbeSBoris Popov  * SUCH DAMAGE.
31681a5bbeSBoris Popov  *
32681a5bbeSBoris Popov  * $FreeBSD$
33681a5bbeSBoris Popov  */
34681a5bbeSBoris Popov 
35681a5bbeSBoris Popov #include <sys/param.h>
36681a5bbeSBoris Popov #include <sys/systm.h>
37681a5bbeSBoris Popov #include <sys/proc.h>
38681a5bbeSBoris Popov #include <sys/bio.h>
39681a5bbeSBoris Popov #include <sys/buf.h>
40681a5bbeSBoris Popov #include <sys/kernel.h>
41681a5bbeSBoris Popov #include <sys/sysctl.h>
42681a5bbeSBoris Popov #include <sys/vnode.h>
43681a5bbeSBoris Popov #include <sys/mount.h>
44681a5bbeSBoris Popov #include <sys/stat.h>
45681a5bbeSBoris Popov #include <sys/malloc.h>
4653f09e72SSheldon Hearn #include <sys/module.h>
47681a5bbeSBoris Popov 
48681a5bbeSBoris Popov 
49681a5bbeSBoris Popov #include <netsmb/smb.h>
50681a5bbeSBoris Popov #include <netsmb/smb_conn.h>
51681a5bbeSBoris Popov #include <netsmb/smb_subr.h>
52681a5bbeSBoris Popov #include <netsmb/smb_dev.h>
53681a5bbeSBoris Popov 
54681a5bbeSBoris Popov #include <fs/smbfs/smbfs.h>
55681a5bbeSBoris Popov #include <fs/smbfs/smbfs_node.h>
56681a5bbeSBoris Popov #include <fs/smbfs/smbfs_subr.h>
57681a5bbeSBoris Popov 
58f70f851cSPoul-Henning Kamp static int smbfs_debuglevel = 0;
59681a5bbeSBoris Popov 
60681a5bbeSBoris Popov static int smbfs_version = SMBFS_VERSION;
61681a5bbeSBoris Popov 
62681a5bbeSBoris Popov #ifdef SMBFS_USEZONE
63681a5bbeSBoris Popov #include <vm/vm.h>
64681a5bbeSBoris Popov #include <vm/vm_extern.h>
65681a5bbeSBoris Popov 
66681a5bbeSBoris Popov vm_zone_t smbfsmount_zone;
67681a5bbeSBoris Popov #endif
68681a5bbeSBoris Popov 
69681a5bbeSBoris Popov SYSCTL_NODE(_vfs, OID_AUTO, smbfs, CTLFLAG_RW, 0, "SMB/CIFS filesystem");
70681a5bbeSBoris Popov SYSCTL_INT(_vfs_smbfs, OID_AUTO, version, CTLFLAG_RD, &smbfs_version, 0, "");
71681a5bbeSBoris Popov SYSCTL_INT(_vfs_smbfs, OID_AUTO, debuglevel, CTLFLAG_RW, &smbfs_debuglevel, 0, "");
72681a5bbeSBoris Popov 
735bb84bc8SRobert Watson static MALLOC_DEFINE(M_SMBFSHASH, "smbfs_hash", "SMBFS hash table");
74681a5bbeSBoris Popov 
757652131bSPoul-Henning Kamp static vfs_init_t       smbfs_init;
767652131bSPoul-Henning Kamp static vfs_uninit_t     smbfs_uninit;
77d14c8441SPoul-Henning Kamp static vfs_cmount_t     smbfs_cmount;
78d14c8441SPoul-Henning Kamp static vfs_mount_t      smbfs_mount;
797652131bSPoul-Henning Kamp static vfs_root_t       smbfs_root;
807652131bSPoul-Henning Kamp static vfs_quotactl_t   smbfs_quotactl;
817652131bSPoul-Henning Kamp static vfs_statfs_t     smbfs_statfs;
827652131bSPoul-Henning Kamp static vfs_unmount_t    smbfs_unmount;
83681a5bbeSBoris Popov 
84681a5bbeSBoris Popov static struct vfsops smbfs_vfsops = {
857652131bSPoul-Henning Kamp 	.vfs_init =		smbfs_init,
86d14c8441SPoul-Henning Kamp 	.vfs_cmount =		smbfs_cmount,
87d14c8441SPoul-Henning Kamp 	.vfs_mount =		smbfs_mount,
887652131bSPoul-Henning Kamp 	.vfs_quotactl =		smbfs_quotactl,
897652131bSPoul-Henning Kamp 	.vfs_root =		smbfs_root,
907652131bSPoul-Henning Kamp 	.vfs_statfs =		smbfs_statfs,
917652131bSPoul-Henning Kamp 	.vfs_sync =		vfs_stdsync,
927652131bSPoul-Henning Kamp 	.vfs_uninit =		smbfs_uninit,
937652131bSPoul-Henning Kamp 	.vfs_unmount =		smbfs_unmount,
94681a5bbeSBoris Popov };
95681a5bbeSBoris Popov 
96681a5bbeSBoris Popov 
97681a5bbeSBoris Popov VFS_SET(smbfs_vfsops, smbfs, VFCF_NETWORK);
98681a5bbeSBoris Popov 
99681a5bbeSBoris Popov MODULE_DEPEND(smbfs, netsmb, NSMB_VERSION, NSMB_VERSION, NSMB_VERSION);
100c4f02a89SMax Khon MODULE_DEPEND(smbfs, libiconv, 1, 1, 2);
10153f09e72SSheldon Hearn MODULE_DEPEND(smbfs, libmchain, 1, 1, 1);
102681a5bbeSBoris Popov 
103681a5bbeSBoris Popov int smbfs_pbuf_freecnt = -1;	/* start out unlimited */
104681a5bbeSBoris Popov 
105681a5bbeSBoris Popov static int
106d14c8441SPoul-Henning Kamp smbfs_cmount(struct mntarg *ma, void * data, int flags, struct thread *td)
107681a5bbeSBoris Popov {
108d14c8441SPoul-Henning Kamp 	struct smbfs_args args;
109681a5bbeSBoris Popov 	int error;
11064042a76SPoul-Henning Kamp 
1110430a5e2SDag-Erling Smørgrav 	error = copyin(data, &args, sizeof(struct smbfs_args));
112681a5bbeSBoris Popov 	if (error)
113681a5bbeSBoris Popov 		return error;
114d14c8441SPoul-Henning Kamp 
115681a5bbeSBoris Popov 	if (args.version != SMBFS_VERSION) {
116681a5bbeSBoris Popov 		printf("mount version mismatch: kernel=%d, mount=%d\n",
117681a5bbeSBoris Popov 		    SMBFS_VERSION, args.version);
118681a5bbeSBoris Popov 		return EINVAL;
119681a5bbeSBoris Popov 	}
120d14c8441SPoul-Henning Kamp 	ma = mount_argf(ma, "dev", "%d", args.dev);
121d14c8441SPoul-Henning Kamp 	ma = mount_argb(ma, args.flags & SMBFS_MOUNT_SOFT, "nosoft");
122d14c8441SPoul-Henning Kamp 	ma = mount_argb(ma, args.flags & SMBFS_MOUNT_INTR, "nointr");
123d14c8441SPoul-Henning Kamp 	ma = mount_argb(ma, args.flags & SMBFS_MOUNT_STRONG, "nostrong");
124d14c8441SPoul-Henning Kamp 	ma = mount_argb(ma, args.flags & SMBFS_MOUNT_HAVE_NLS, "nohave_nls");
125d14c8441SPoul-Henning Kamp 	ma = mount_argb(ma, !(args.flags & SMBFS_MOUNT_NO_LONG), "nolong");
126d14c8441SPoul-Henning Kamp 	ma = mount_arg(ma, "rootpath", args.root_path, -1);
127d14c8441SPoul-Henning Kamp 	ma = mount_argf(ma, "uid", "%d", args.uid);
128d14c8441SPoul-Henning Kamp 	ma = mount_argf(ma, "gid", "%d", args.gid);
129d14c8441SPoul-Henning Kamp 	ma = mount_argf(ma, "file_mode", "%d", args.file_mode);
130d14c8441SPoul-Henning Kamp 	ma = mount_argf(ma, "dir_mode", "%d", args.dir_mode);
131d14c8441SPoul-Henning Kamp 	ma = mount_argf(ma, "caseopt", "%d", args.caseopt);
132d14c8441SPoul-Henning Kamp 
133d14c8441SPoul-Henning Kamp 	error = kernel_mount(ma, flags);
134d14c8441SPoul-Henning Kamp 
135d14c8441SPoul-Henning Kamp 	return (error);
136d14c8441SPoul-Henning Kamp }
137d14c8441SPoul-Henning Kamp 
138d14c8441SPoul-Henning Kamp static const char *smbfs_opts[] = {
139708394ecSPoul-Henning Kamp 	"dev", "soft", "intr", "strong", "have_nls", "long",
140d14c8441SPoul-Henning Kamp 	"mountpoint", "rootpath", "uid", "gid", "file_mode", "dir_mode",
14143fa5bf5SCraig Rodrigues 	"caseopt", "errmsg", NULL
142d14c8441SPoul-Henning Kamp };
143d14c8441SPoul-Henning Kamp 
144d14c8441SPoul-Henning Kamp static int
145d14c8441SPoul-Henning Kamp smbfs_mount(struct mount *mp, struct thread *td)
146d14c8441SPoul-Henning Kamp {
147d14c8441SPoul-Henning Kamp 	struct smbmount *smp = NULL;
148d14c8441SPoul-Henning Kamp 	struct smb_vc *vcp;
149d14c8441SPoul-Henning Kamp 	struct smb_share *ssp = NULL;
150d14c8441SPoul-Henning Kamp 	struct vnode *vp;
151d14c8441SPoul-Henning Kamp 	struct smb_cred scred;
152d14c8441SPoul-Henning Kamp 	int error, v;
153d14c8441SPoul-Henning Kamp 	char *pc, *pe;
154d14c8441SPoul-Henning Kamp 
155d14c8441SPoul-Henning Kamp 	if (mp->mnt_flag & (MNT_UPDATE | MNT_ROOTFS))
156d14c8441SPoul-Henning Kamp 		return EOPNOTSUPP;
157d14c8441SPoul-Henning Kamp 
15843fa5bf5SCraig Rodrigues 	if (vfs_filteropt(mp->mnt_optnew, smbfs_opts)) {
15943fa5bf5SCraig Rodrigues 		vfs_mount_error(mp, "%s", "Invalid option");
160d14c8441SPoul-Henning Kamp 		return (EINVAL);
16143fa5bf5SCraig Rodrigues 	}
162d14c8441SPoul-Henning Kamp 
163a854ed98SJohn Baldwin 	smb_makescred(&scred, td, td->td_ucred);
16443fa5bf5SCraig Rodrigues 	if (1 != vfs_scanopt(mp->mnt_optnew, "dev", "%d", &v)) {
16543fa5bf5SCraig Rodrigues 		vfs_mount_error(mp, "No dev option");
166d14c8441SPoul-Henning Kamp 		return (EINVAL);
16743fa5bf5SCraig Rodrigues 	}
168d14c8441SPoul-Henning Kamp 	error = smb_dev2share(v, SMBM_EXEC, &scred, &ssp);
169681a5bbeSBoris Popov 	if (error) {
170d14c8441SPoul-Henning Kamp 		printf("invalid device handle %d (%d)\n", v, error);
17143fa5bf5SCraig Rodrigues 		vfs_mount_error(mp, "invalid device handle %d (%d)\n", v, error);
172681a5bbeSBoris Popov 		return error;
173681a5bbeSBoris Popov 	}
174681a5bbeSBoris Popov 	vcp = SSTOVC(ssp);
175b1c996c4SBoris Popov 	smb_share_unlock(ssp, 0, td);
176681a5bbeSBoris Popov 	mp->mnt_stat.f_iosize = SSTOVC(ssp)->vc_txmax;
177681a5bbeSBoris Popov 
178681a5bbeSBoris Popov #ifdef SMBFS_USEZONE
179681a5bbeSBoris Popov 	smp = zalloc(smbfsmount_zone);
180681a5bbeSBoris Popov #else
181788fc48eSTim J. Robbins 	MALLOC(smp, struct smbmount*, sizeof(*smp), M_SMBFSDATA,
182788fc48eSTim J. Robbins 	    M_WAITOK|M_USE_RESERVE);
183681a5bbeSBoris Popov #endif
184681a5bbeSBoris Popov         if (smp == NULL) {
185681a5bbeSBoris Popov 		printf("could not alloc smbmount\n");
18643fa5bf5SCraig Rodrigues 		vfs_mount_error(mp, "could not alloc smbmount", v, error);
187681a5bbeSBoris Popov 		error = ENOMEM;
188681a5bbeSBoris Popov 		goto bad;
189681a5bbeSBoris Popov         }
190681a5bbeSBoris Popov 	bzero(smp, sizeof(*smp));
191681a5bbeSBoris Popov         mp->mnt_data = (qaddr_t)smp;
192681a5bbeSBoris Popov 	smp->sm_hash = hashinit(desiredvnodes, M_SMBFSHASH, &smp->sm_hashlen);
193681a5bbeSBoris Popov 	if (smp->sm_hash == NULL)
194681a5bbeSBoris Popov 		goto bad;
195681a5bbeSBoris Popov 	lockinit(&smp->sm_hashlock, PVFS, "smbfsh", 0, 0);
196681a5bbeSBoris Popov 	smp->sm_share = ssp;
197681a5bbeSBoris Popov 	smp->sm_root = NULL;
198d14c8441SPoul-Henning Kamp 	if (1 != vfs_scanopt(mp->mnt_optnew,
199d14c8441SPoul-Henning Kamp 	    "caseopt", "%d", &smp->sm_caseopt)) {
20043fa5bf5SCraig Rodrigues 		vfs_mount_error(mp, "Invalid caseopt");
201d14c8441SPoul-Henning Kamp 		error = EINVAL;
202d14c8441SPoul-Henning Kamp 		goto bad;
203d14c8441SPoul-Henning Kamp 	}
204d14c8441SPoul-Henning Kamp 	if (1 != vfs_scanopt(mp->mnt_optnew, "uid", "%d", &v)) {
20543fa5bf5SCraig Rodrigues 		vfs_mount_error(mp, "Invalid uid");
206d14c8441SPoul-Henning Kamp 		error = EINVAL;
207d14c8441SPoul-Henning Kamp 		goto bad;
208d14c8441SPoul-Henning Kamp 	}
209d14c8441SPoul-Henning Kamp 	smp->sm_uid = v;
210d14c8441SPoul-Henning Kamp 
211d14c8441SPoul-Henning Kamp 	if (1 != vfs_scanopt(mp->mnt_optnew, "gid", "%d", &v)) {
21243fa5bf5SCraig Rodrigues 		vfs_mount_error(mp, "Invalid gid");
213d14c8441SPoul-Henning Kamp 		error = EINVAL;
214d14c8441SPoul-Henning Kamp 		goto bad;
215d14c8441SPoul-Henning Kamp 	}
216d14c8441SPoul-Henning Kamp 	smp->sm_gid = v;
217d14c8441SPoul-Henning Kamp 
218d14c8441SPoul-Henning Kamp 	if (1 != vfs_scanopt(mp->mnt_optnew, "file_mode", "%d", &v)) {
21943fa5bf5SCraig Rodrigues 		vfs_mount_error(mp, "Invalid file_mode");
220d14c8441SPoul-Henning Kamp 		error = EINVAL;
221d14c8441SPoul-Henning Kamp 		goto bad;
222d14c8441SPoul-Henning Kamp 	}
223d14c8441SPoul-Henning Kamp 	smp->sm_file_mode = (v & (S_IRWXU|S_IRWXG|S_IRWXO)) | S_IFREG;
224d14c8441SPoul-Henning Kamp 
225d14c8441SPoul-Henning Kamp 	if (1 != vfs_scanopt(mp->mnt_optnew, "dir_mode", "%d", &v)) {
22643fa5bf5SCraig Rodrigues 		vfs_mount_error(mp, "Invalid dir_mode");
227d14c8441SPoul-Henning Kamp 		error = EINVAL;
228d14c8441SPoul-Henning Kamp 		goto bad;
229d14c8441SPoul-Henning Kamp 	}
230d14c8441SPoul-Henning Kamp 	smp->sm_dir_mode  = (v & (S_IRWXU|S_IRWXG|S_IRWXO)) | S_IFDIR;
231d14c8441SPoul-Henning Kamp 
232d14c8441SPoul-Henning Kamp 	vfs_flagopt(mp->mnt_optnew,
2338bfc2304STai-hwa Liang 	    "nolong", &smp->sm_flags, SMBFS_MOUNT_NO_LONG);
234681a5bbeSBoris Popov 
235681a5bbeSBoris Popov /*	simple_lock_init(&smp->sm_npslock);*/
236681a5bbeSBoris Popov 	pc = mp->mnt_stat.f_mntfromname;
237681a5bbeSBoris Popov 	pe = pc + sizeof(mp->mnt_stat.f_mntfromname);
238681a5bbeSBoris Popov 	bzero(pc, MNAMELEN);
239681a5bbeSBoris Popov 	*pc++ = '/';
240681a5bbeSBoris Popov 	*pc++ = '/';
241681a5bbeSBoris Popov 	pc=index(strncpy(pc, vcp->vc_username, pe - pc - 2), 0);
242681a5bbeSBoris Popov 	if (pc < pe-1) {
243681a5bbeSBoris Popov 		*(pc++) = '@';
244681a5bbeSBoris Popov 		pc = index(strncpy(pc, vcp->vc_srvname, pe - pc - 2), 0);
245681a5bbeSBoris Popov 		if (pc < pe - 1) {
246681a5bbeSBoris Popov 			*(pc++) = '/';
247681a5bbeSBoris Popov 			strncpy(pc, ssp->ss_name, pe - pc - 2);
248681a5bbeSBoris Popov 		}
249681a5bbeSBoris Popov 	}
250681a5bbeSBoris Popov 	vfs_getnewfsid(mp);
251d9b2d9f7SJeff Roberson 	error = smbfs_root(mp, LK_EXCLUSIVE, &vp, td);
25243fa5bf5SCraig Rodrigues 	if (error) {
25343fa5bf5SCraig Rodrigues 		vfs_mount_error(mp, "smbfs_root error: %d", error);
254681a5bbeSBoris Popov 		goto bad;
25543fa5bf5SCraig Rodrigues 	}
256b1c996c4SBoris Popov 	VOP_UNLOCK(vp, 0, td);
2574d93c0beSJeff Roberson 	SMBVDEBUG("root.v_usecount = %d\n", vrefcnt(vp));
258681a5bbeSBoris Popov 
259681a5bbeSBoris Popov #ifdef DIAGNOSTICS
260681a5bbeSBoris Popov 	SMBERROR("mp=%p\n", mp);
261681a5bbeSBoris Popov #endif
262681a5bbeSBoris Popov 	return error;
263681a5bbeSBoris Popov bad:
264681a5bbeSBoris Popov         if (smp) {
265681a5bbeSBoris Popov 		if (smp->sm_hash)
266681a5bbeSBoris Popov 			free(smp->sm_hash, M_SMBFSHASH);
267681a5bbeSBoris Popov 		lockdestroy(&smp->sm_hashlock);
268681a5bbeSBoris Popov #ifdef SMBFS_USEZONE
269681a5bbeSBoris Popov 		zfree(smbfsmount_zone, smp);
270681a5bbeSBoris Popov #else
271681a5bbeSBoris Popov 		free(smp, M_SMBFSDATA);
272681a5bbeSBoris Popov #endif
273681a5bbeSBoris Popov 	}
274681a5bbeSBoris Popov 	if (ssp)
275681a5bbeSBoris Popov 		smb_share_put(ssp, &scred);
276681a5bbeSBoris Popov         return error;
277681a5bbeSBoris Popov }
278681a5bbeSBoris Popov 
279681a5bbeSBoris Popov /* Unmount the filesystem described by mp. */
280681a5bbeSBoris Popov static int
281b1c996c4SBoris Popov smbfs_unmount(struct mount *mp, int mntflags, struct thread *td)
282681a5bbeSBoris Popov {
283681a5bbeSBoris Popov 	struct smbmount *smp = VFSTOSMBFS(mp);
284681a5bbeSBoris Popov 	struct smb_cred scred;
285681a5bbeSBoris Popov 	int error, flags;
286681a5bbeSBoris Popov 
287681a5bbeSBoris Popov 	SMBVDEBUG("smbfs_unmount: flags=%04x\n", mntflags);
288681a5bbeSBoris Popov 	flags = 0;
289681a5bbeSBoris Popov 	if (mntflags & MNT_FORCE)
290681a5bbeSBoris Popov 		flags |= FORCECLOSE;
291578dcf0cSTim J. Robbins 	/*
292578dcf0cSTim J. Robbins 	 * Keep trying to flush the vnode list for the mount while
293578dcf0cSTim J. Robbins 	 * some are still busy and we are making progress towards
294578dcf0cSTim J. Robbins 	 * making them not busy. This is needed because smbfs vnodes
295578dcf0cSTim J. Robbins 	 * reference their parent directory but may appear after their
296578dcf0cSTim J. Robbins 	 * parent in the list; one pass over the vnode list is not
297578dcf0cSTim J. Robbins 	 * sufficient in this case.
298578dcf0cSTim J. Robbins 	 */
299578dcf0cSTim J. Robbins 	do {
300578dcf0cSTim J. Robbins 		smp->sm_didrele = 0;
3010864ef1eSIan Dowse 		/* There is 1 extra root vnode reference from smbfs_mount(). */
302f257b7a5SAlfred Perlstein 		error = vflush(mp, 1, flags, td);
303578dcf0cSTim J. Robbins 	} while (error == EBUSY && smp->sm_didrele != 0);
304681a5bbeSBoris Popov 	if (error)
305681a5bbeSBoris Popov 		return error;
306a854ed98SJohn Baldwin 	smb_makescred(&scred, td, td->td_ucred);
307681a5bbeSBoris Popov 	smb_share_put(smp->sm_share, &scred);
308681a5bbeSBoris Popov 	mp->mnt_data = (qaddr_t)0;
309681a5bbeSBoris Popov 
310681a5bbeSBoris Popov 	if (smp->sm_hash)
311681a5bbeSBoris Popov 		free(smp->sm_hash, M_SMBFSHASH);
312681a5bbeSBoris Popov 	lockdestroy(&smp->sm_hashlock);
313681a5bbeSBoris Popov #ifdef SMBFS_USEZONE
314681a5bbeSBoris Popov 	zfree(smbfsmount_zone, smp);
315681a5bbeSBoris Popov #else
316681a5bbeSBoris Popov 	free(smp, M_SMBFSDATA);
317681a5bbeSBoris Popov #endif
318681a5bbeSBoris Popov 	mp->mnt_flag &= ~MNT_LOCAL;
319681a5bbeSBoris Popov 	return error;
320681a5bbeSBoris Popov }
321681a5bbeSBoris Popov 
322681a5bbeSBoris Popov /*
323681a5bbeSBoris Popov  * Return locked root vnode of a filesystem
324681a5bbeSBoris Popov  */
325681a5bbeSBoris Popov static int
326d9b2d9f7SJeff Roberson smbfs_root(struct mount *mp, int flags, struct vnode **vpp, struct thread *td)
327681a5bbeSBoris Popov {
328681a5bbeSBoris Popov 	struct smbmount *smp = VFSTOSMBFS(mp);
329681a5bbeSBoris Popov 	struct vnode *vp;
330681a5bbeSBoris Popov 	struct smbnode *np;
331681a5bbeSBoris Popov 	struct smbfattr fattr;
332a854ed98SJohn Baldwin 	struct ucred *cred = td->td_ucred;
333681a5bbeSBoris Popov 	struct smb_cred scred;
334681a5bbeSBoris Popov 	int error;
335681a5bbeSBoris Popov 
336681a5bbeSBoris Popov 	if (smp == NULL) {
337681a5bbeSBoris Popov 		SMBERROR("smp == NULL (bug in umount)\n");
33843fa5bf5SCraig Rodrigues 		vfs_mount_error(mp, "smp == NULL (bug in umount)");
339681a5bbeSBoris Popov 		return EINVAL;
340681a5bbeSBoris Popov 	}
341681a5bbeSBoris Popov 	if (smp->sm_root) {
342681a5bbeSBoris Popov 		*vpp = SMBTOV(smp->sm_root);
343b1c996c4SBoris Popov 		return vget(*vpp, LK_EXCLUSIVE | LK_RETRY, td);
344681a5bbeSBoris Popov 	}
345b1c996c4SBoris Popov 	smb_makescred(&scred, td, cred);
346681a5bbeSBoris Popov 	error = smbfs_smb_lookup(NULL, NULL, 0, &fattr, &scred);
347681a5bbeSBoris Popov 	if (error)
348681a5bbeSBoris Popov 		return error;
349681a5bbeSBoris Popov 	error = smbfs_nget(mp, NULL, "TheRooT", 7, &fattr, &vp);
350681a5bbeSBoris Popov 	if (error)
351681a5bbeSBoris Popov 		return error;
352e6e370a7SJeff Roberson 	ASSERT_VOP_LOCKED(vp, "smbfs_root");
353e6e370a7SJeff Roberson 	vp->v_vflag |= VV_ROOT;
354681a5bbeSBoris Popov 	np = VTOSMB(vp);
355681a5bbeSBoris Popov 	smp->sm_root = np;
356681a5bbeSBoris Popov 	*vpp = vp;
357681a5bbeSBoris Popov 	return 0;
358681a5bbeSBoris Popov }
359681a5bbeSBoris Popov 
3608e67c454STim J. Robbins /*
3618e67c454STim J. Robbins  * Do operations associated with quotas, not supported
3628e67c454STim J. Robbins  */
3638e67c454STim J. Robbins /* ARGSUSED */
3648e67c454STim J. Robbins static int
3658e67c454STim J. Robbins smbfs_quotactl(mp, cmd, uid, arg, td)
3668e67c454STim J. Robbins 	struct mount *mp;
3678e67c454STim J. Robbins 	int cmd;
3688e67c454STim J. Robbins 	uid_t uid;
3690430a5e2SDag-Erling Smørgrav 	void *arg;
3708e67c454STim J. Robbins 	struct thread *td;
3718e67c454STim J. Robbins {
3728e67c454STim J. Robbins 	SMBVDEBUG("return EOPNOTSUPP\n");
3738e67c454STim J. Robbins 	return EOPNOTSUPP;
3748e67c454STim J. Robbins }
3758e67c454STim J. Robbins 
376681a5bbeSBoris Popov /*ARGSUSED*/
377681a5bbeSBoris Popov int
378681a5bbeSBoris Popov smbfs_init(struct vfsconf *vfsp)
379681a5bbeSBoris Popov {
380681a5bbeSBoris Popov #ifdef SMBFS_USEZONE
381681a5bbeSBoris Popov 	smbfsmount_zone = zinit("SMBFSMOUNT", sizeof(struct smbmount), 0, 0, 1);
382681a5bbeSBoris Popov #endif
383681a5bbeSBoris Popov 	smbfs_pbuf_freecnt = nswbuf / 2 + 1;
384681a5bbeSBoris Popov 	SMBVDEBUG("done.\n");
385681a5bbeSBoris Popov 	return 0;
386681a5bbeSBoris Popov }
387681a5bbeSBoris Popov 
3888e67c454STim J. Robbins /*ARGSUSED*/
3898e67c454STim J. Robbins int
3908e67c454STim J. Robbins smbfs_uninit(struct vfsconf *vfsp)
3918e67c454STim J. Robbins {
3928e67c454STim J. Robbins 
3938e67c454STim J. Robbins 	SMBVDEBUG("done.\n");
3948e67c454STim J. Robbins 	return 0;
3958e67c454STim J. Robbins }
3968e67c454STim J. Robbins 
397681a5bbeSBoris Popov /*
398681a5bbeSBoris Popov  * smbfs_statfs call
399681a5bbeSBoris Popov  */
400681a5bbeSBoris Popov int
401b1c996c4SBoris Popov smbfs_statfs(struct mount *mp, struct statfs *sbp, struct thread *td)
402681a5bbeSBoris Popov {
403681a5bbeSBoris Popov 	struct smbmount *smp = VFSTOSMBFS(mp);
404681a5bbeSBoris Popov 	struct smbnode *np = smp->sm_root;
405681a5bbeSBoris Popov 	struct smb_share *ssp = smp->sm_share;
406681a5bbeSBoris Popov 	struct smb_cred scred;
407681a5bbeSBoris Popov 	int error = 0;
408681a5bbeSBoris Popov 
40943fa5bf5SCraig Rodrigues 	if (np == NULL) {
41043fa5bf5SCraig Rodrigues 		vfs_mount_error(mp, "np == NULL");
411681a5bbeSBoris Popov 		return EINVAL;
41243fa5bf5SCraig Rodrigues 	}
413681a5bbeSBoris Popov 
414681a5bbeSBoris Popov 	sbp->f_iosize = SSTOVC(ssp)->vc_txmax;		/* optimal transfer block size */
415a854ed98SJohn Baldwin 	smb_makescred(&scred, td, td->td_ucred);
416681a5bbeSBoris Popov 
417681a5bbeSBoris Popov 	if (SMB_DIALECT(SSTOVC(ssp)) >= SMB_DIALECT_LANMAN2_0)
418681a5bbeSBoris Popov 		error = smbfs_smb_statfs2(ssp, sbp, &scred);
419681a5bbeSBoris Popov 	else
420681a5bbeSBoris Popov 		error = smbfs_smb_statfs(ssp, sbp, &scred);
421681a5bbeSBoris Popov 	if (error)
422681a5bbeSBoris Popov 		return error;
423681a5bbeSBoris Popov 	sbp->f_flags = 0;		/* copy of mount exported flags */
424681a5bbeSBoris Popov 	return 0;
425681a5bbeSBoris Popov }
426