Sync usage with man page.
[netbsd-mini2440.git] / sys / fs / smbfs / smbfs_vfsops.c
blob7275909aebaf43aabcce2d977e149f829db55a7b
1 /* $NetBSD: smbfs_vfsops.c,v 1.89 2009/09/07 12:52:53 pooka Exp $ */
3 /*
4 * Copyright (c) 2000-2001, Boris Popov
5 * All rights reserved.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. All advertising materials mentioning features or use of this software
16 * must display the following acknowledgement:
17 * This product includes software developed by Boris Popov.
18 * 4. Neither the name of the author nor the names of any co-contributors
19 * may be used to endorse or promote products derived from this software
20 * without specific prior written permission.
22 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32 * SUCH DAMAGE.
34 * FreeBSD: src/sys/fs/smbfs/smbfs_vfsops.c,v 1.5 2001/12/13 13:08:34 sheldonh Exp
37 #include <sys/cdefs.h>
38 __KERNEL_RCSID(0, "$NetBSD: smbfs_vfsops.c,v 1.89 2009/09/07 12:52:53 pooka Exp $");
40 #include <sys/param.h>
41 #include <sys/systm.h>
42 #include <sys/proc.h>
43 #include <sys/buf.h>
44 #include <sys/kernel.h>
45 #include <sys/dirent.h>
46 #include <sys/sysctl.h>
47 #include <sys/vnode.h>
48 #include <sys/mount.h>
49 #include <sys/stat.h>
50 #include <sys/malloc.h>
51 #include <sys/kauth.h>
52 #include <sys/module.h>
53 #include <miscfs/genfs/genfs.h>
56 #include <netsmb/smb.h>
57 #include <netsmb/smb_conn.h>
58 #include <netsmb/smb_subr.h>
59 #include <netsmb/smb_dev.h>
61 #include <fs/smbfs/smbfs.h>
62 #include <fs/smbfs/smbfs_node.h>
63 #include <fs/smbfs/smbfs_subr.h>
65 MODULE(MODULE_CLASS_VFS, smbfs, NULL);
67 VFS_PROTOS(smbfs);
69 static struct sysctllog *smbfs_sysctl_log;
71 static int smbfs_setroot(struct mount *);
73 extern struct vnodeopv_desc smbfs_vnodeop_opv_desc;
75 static const struct vnodeopv_desc *smbfs_vnodeopv_descs[] = {
76 &smbfs_vnodeop_opv_desc,
77 NULL,
80 struct vfsops smbfs_vfsops = {
81 MOUNT_SMBFS,
82 sizeof (struct smbfs_args),
83 smbfs_mount,
84 smbfs_start,
85 smbfs_unmount,
86 smbfs_root,
87 (void *)eopnotsupp, /* vfs_quotactl */
88 smbfs_statvfs,
89 smbfs_sync,
90 smbfs_vget,
91 (void *)eopnotsupp, /* vfs_fhtovp */
92 (void *)eopnotsupp, /* vfs_vptofh */
93 smbfs_init,
94 smbfs_reinit,
95 smbfs_done,
96 (int (*) (void)) eopnotsupp, /* mountroot */
97 (int (*)(struct mount *, struct vnode *, struct timespec *)) eopnotsupp,
98 vfs_stdextattrctl,
99 (void *)eopnotsupp, /* vfs_suspendctl */
100 genfs_renamelock_enter,
101 genfs_renamelock_exit,
102 (void *)eopnotsupp,
103 smbfs_vnodeopv_descs,
104 0, /* vfs_refcount */
105 { NULL, NULL },
108 static int
109 smbfs_modcmd(modcmd_t cmd, void *arg)
111 const struct sysctlnode *smb = NULL;
112 int error;
114 switch (cmd) {
115 case MODULE_CMD_INIT:
116 error = vfs_attach(&smbfs_vfsops);
117 if (error != 0)
118 break;
119 sysctl_createv(&smbfs_sysctl_log, 0, NULL, NULL,
120 CTLFLAG_PERMANENT,
121 CTLTYPE_NODE, "vfs", NULL,
122 NULL, 0, NULL, 0,
123 CTL_VFS, CTL_EOL);
124 sysctl_createv(&smbfs_sysctl_log, 0, NULL, &smb,
125 CTLFLAG_PERMANENT,
126 CTLTYPE_NODE, "samba",
127 SYSCTL_DESCR("SMB/CIFS remote file system"),
128 NULL, 0, NULL, 0,
129 CTL_VFS, CTL_CREATE, CTL_EOL);
131 if (smb != NULL) {
132 sysctl_createv(&smbfs_sysctl_log, 0, &smb, NULL,
133 CTLFLAG_PERMANENT|CTLFLAG_IMMEDIATE,
134 CTLTYPE_INT, "version",
135 SYSCTL_DESCR("smbfs version"),
136 NULL, SMBFS_VERSION, NULL, 0,
137 CTL_CREATE, CTL_EOL);
139 break;
140 case MODULE_CMD_FINI:
141 error = vfs_detach(&smbfs_vfsops);
142 if (error != 0)
143 break;
144 sysctl_teardown(&smbfs_sysctl_log);
145 break;
146 default:
147 error = ENOTTY;
148 break;
151 return (error);
155 smbfs_mount(struct mount *mp, const char *path, void *data, size_t *data_len)
157 struct lwp *l = curlwp;
158 struct smbfs_args *args = data; /* holds data from mount request */
159 struct smbmount *smp = NULL;
160 struct smb_vc *vcp;
161 struct smb_share *ssp = NULL;
162 struct smb_cred scred;
163 struct proc *p;
164 char *fromname;
165 int error;
167 if (*data_len < sizeof *args)
168 return EINVAL;
170 p = l->l_proc;
171 if (mp->mnt_flag & MNT_GETARGS) {
172 smp = VFSTOSMBFS(mp);
173 if (smp == NULL)
174 return EIO;
175 *args = smp->sm_args;
176 *data_len = sizeof *args;
177 return 0;
180 if (mp->mnt_flag & MNT_UPDATE)
181 return EOPNOTSUPP;
183 if (args->version != SMBFS_VERSION) {
184 SMBVDEBUG("mount version mismatch: kernel=%d, mount=%d\n",
185 SMBFS_VERSION, args->version);
186 return EINVAL;
189 smb_makescred(&scred, l, l->l_cred);
190 error = smb_dev2share(args->dev_fd, SMBM_EXEC, &scred, &ssp);
191 if (error)
192 return error;
193 smb_share_unlock(ssp); /* keep ref, but unlock */
194 vcp = SSTOVC(ssp);
196 fromname = kmem_zalloc(MNAMELEN, KM_SLEEP);
197 snprintf(fromname, MNAMELEN,
198 "//%s@%s/%s", vcp->vc_username, vcp->vc_srvname, ssp->ss_name);
199 error = set_statvfs_info(path, UIO_USERSPACE, fromname, UIO_SYSSPACE,
200 mp->mnt_op->vfs_name, mp, l);
201 kmem_free(fromname, MNAMELEN);
202 if (error) {
203 smb_share_lock(ssp);
204 smb_share_put(ssp, &scred);
205 return error;
208 mp->mnt_stat.f_iosize = vcp->vc_txmax;
209 mp->mnt_stat.f_namemax =
210 (vcp->vc_hflags2 & SMB_FLAGS2_KNOWS_LONG_NAMES) ? 255 : 12;
212 smp = malloc(sizeof(*smp), M_SMBFSDATA, M_WAITOK|M_ZERO);
213 mp->mnt_data = smp;
215 smp->sm_hash = hashinit(desiredvnodes, HASH_LIST, true,
216 &smp->sm_hashlen);
218 mutex_init(&smp->sm_hashlock, MUTEX_DEFAULT, IPL_NONE);
219 smp->sm_share = ssp;
220 smp->sm_root = NULL;
221 smp->sm_args = *args;
222 smp->sm_caseopt = args->caseopt;
223 smp->sm_args.file_mode = (smp->sm_args.file_mode &
224 (S_IRWXU|S_IRWXG|S_IRWXO)) | S_IFREG;
225 smp->sm_args.dir_mode = (smp->sm_args.dir_mode &
226 (S_IRWXU|S_IRWXG|S_IRWXO)) | S_IFDIR;
228 vfs_getnewfsid(mp);
229 return (0);
232 /* Unmount the filesystem described by mp. */
234 smbfs_unmount(struct mount *mp, int mntflags)
236 struct lwp *l = curlwp;
237 struct smbmount *smp = VFSTOSMBFS(mp);
238 struct smb_cred scred;
239 struct vnode *smbfs_rootvp = SMBTOV(smp->sm_root);
240 int error, flags;
242 SMBVDEBUG("smbfs_unmount: flags=%04x\n", mntflags);
243 flags = 0;
244 if (mntflags & MNT_FORCE)
245 flags |= FORCECLOSE;
247 if (smbfs_rootvp->v_usecount > 1 && (mntflags & MNT_FORCE) == 0)
248 return EBUSY;
250 /* Flush all vnodes.
251 * Keep trying to flush the vnode list for the mount while
252 * some are still busy and we are making progress towards
253 * making them not busy. This is needed because smbfs vnodes
254 * reference their parent directory but may appear after their
255 * parent in the list; one pass over the vnode list is not
256 * sufficient in this case. */
257 do {
258 smp->sm_didrele = 0;
259 error = vflush(mp, smbfs_rootvp, flags);
260 } while (error == EBUSY && smp->sm_didrele != 0);
261 if (error)
262 return error;
264 vgone(smbfs_rootvp);
266 smb_makescred(&scred, l, l->l_cred);
267 smb_share_lock(smp->sm_share);
268 smb_share_put(smp->sm_share, &scred);
269 mp->mnt_data = NULL;
271 hashdone(smp->sm_hash, HASH_LIST, smp->sm_hashlen);
272 mutex_destroy(&smp->sm_hashlock);
273 free(smp, M_SMBFSDATA);
274 return 0;
278 * Get root vnode of the smbfs filesystem, and store it in sm_root.
280 static int
281 smbfs_setroot(struct mount *mp)
283 struct smbmount *smp = VFSTOSMBFS(mp);
284 struct vnode *vp;
285 struct smbfattr fattr;
286 struct lwp *l = curlwp;
287 kauth_cred_t cred = l->l_cred;
288 struct smb_cred scred;
289 int error;
291 KASSERT(smp->sm_root == NULL);
293 smb_makescred(&scred, l, cred);
294 error = smbfs_smb_lookup(NULL, NULL, 0, &fattr, &scred);
295 if (error)
296 return error;
297 error = smbfs_nget(mp, NULL, "TheRooT", 7, &fattr, &vp);
298 if (error)
299 return error;
302 * Someone might have already set sm_root while we slept
303 * in smb_lookup or malloc/getnewvnode.
305 if (smp->sm_root)
306 vput(vp);
307 else {
308 vp->v_vflag |= VV_ROOT;
309 smp->sm_root = VTOSMB(vp);
311 /* Keep reference, but unlock */
312 VOP_UNLOCK(vp, 0);
315 return (0);
319 * Return locked root vnode of a filesystem.
322 smbfs_root(struct mount *mp, struct vnode **vpp)
324 struct smbmount *smp = VFSTOSMBFS(mp);
326 if (__predict_false(!smp->sm_root)) {
327 int error = smbfs_setroot(mp);
328 if (error)
329 return (error);
330 /* fallthrough */
333 KASSERT(smp->sm_root != NULL && SMBTOV(smp->sm_root) != NULL);
334 *vpp = SMBTOV(smp->sm_root);
335 return vget(*vpp, LK_EXCLUSIVE | LK_RETRY);
339 * Make a filesystem operational.
340 * Nothing to do at the moment.
342 /* ARGSUSED */
344 smbfs_start(struct mount *mp, int flags)
346 SMBVDEBUG("flags=%04x\n", flags);
347 return 0;
350 void
351 smbfs_init(void)
354 malloc_type_attach(M_SMBNODENAME);
355 malloc_type_attach(M_SMBFSDATA);
356 pool_init(&smbfs_node_pool, sizeof(struct smbnode), 0, 0, 0,
357 "smbfsnopl", &pool_allocator_nointr, IPL_NONE);
359 SMBVDEBUG0("init.\n");
362 void
363 smbfs_reinit(void)
366 SMBVDEBUG0("reinit.\n");
369 void
370 smbfs_done(void)
373 pool_destroy(&smbfs_node_pool);
374 malloc_type_detach(M_SMBNODENAME);
375 malloc_type_detach(M_SMBFSDATA);
377 SMBVDEBUG0("done.\n");
381 * smbfs_statvfs call
384 smbfs_statvfs(struct mount *mp, struct statvfs *sbp)
386 struct lwp *l = curlwp;
387 struct smbmount *smp = VFSTOSMBFS(mp);
388 struct smb_share *ssp = smp->sm_share;
389 struct smb_cred scred;
390 int error = 0;
392 sbp->f_iosize = SSTOVC(ssp)->vc_txmax; /* optimal transfer block size */
393 smb_makescred(&scred, l, l->l_cred);
395 error = smbfs_smb_statvfs(ssp, sbp, &scred);
396 if (error)
397 return error;
399 sbp->f_flag = 0; /* copy of mount exported flags */
400 sbp->f_owner = mp->mnt_stat.f_owner; /* user that mounted the filesystem */
401 copy_statvfs_info(sbp, mp);
402 return 0;
406 * Flush out the buffer cache
409 smbfs_sync(struct mount *mp, int waitfor, kauth_cred_t cred)
411 struct vnode *vp, *mvp;
412 struct smbnode *np;
413 int error, allerror = 0;
415 /* Allocate a marker vnode. */
416 if ((mvp = vnalloc(mp)) == NULL)
417 return ENOMEM;
419 * Force stale buffer cache information to be flushed.
421 mutex_enter(&mntvnode_lock);
422 loop:
423 for (vp = TAILQ_FIRST(&mp->mnt_vnodelist); vp; vp = vunmark(mvp)) {
424 vmark(mvp, vp);
426 * If the vnode that we are about to sync is no longer
427 * associated with this mount point, start over.
429 if (vp->v_mount != mp || vismarker(vp))
430 continue;
431 mutex_enter(&vp->v_interlock);
432 np = VTOSMB(vp);
433 if (np == NULL) {
434 mutex_exit(&vp->v_interlock);
435 continue;
437 if ((vp->v_type == VNON || (np->n_flag & NMODIFIED) == 0) &&
438 LIST_EMPTY(&vp->v_dirtyblkhd) &&
439 vp->v_uobj.uo_npages == 0) {
440 mutex_exit(&vp->v_interlock);
441 continue;
443 mutex_exit(&mntvnode_lock);
444 error = vget(vp, LK_EXCLUSIVE | LK_NOWAIT | LK_INTERLOCK);
445 if (error) {
446 mutex_enter(&mntvnode_lock);
447 if (error == ENOENT) {
448 (void)vunmark(mvp);
449 goto loop;
451 continue;
453 error = VOP_FSYNC(vp, cred,
454 waitfor == MNT_WAIT ? FSYNC_WAIT : 0, 0, 0);
455 if (error)
456 allerror = error;
457 vput(vp);
458 mutex_enter(&mntvnode_lock);
460 mutex_exit(&mntvnode_lock);
461 vnfree(mvp);
462 return (allerror);
465 #if __FreeBSD_version < 400009
467 * smbfs flat namespace lookup. Unsupported.
469 /* ARGSUSED */
470 int smbfs_vget(struct mount *mp, ino_t ino,
471 struct vnode **vpp)
473 return (EOPNOTSUPP);
476 #endif /* __FreeBSD_version < 400009 */