1 /* $NetBSD: smbfs_vfsops.c,v 1.89 2009/09/07 12:52:53 pooka Exp $ */
4 * Copyright (c) 2000-2001, Boris Popov
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
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
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>
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>
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
);
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
,
80 struct vfsops smbfs_vfsops
= {
82 sizeof (struct smbfs_args
),
87 (void *)eopnotsupp
, /* vfs_quotactl */
91 (void *)eopnotsupp
, /* vfs_fhtovp */
92 (void *)eopnotsupp
, /* vfs_vptofh */
96 (int (*) (void)) eopnotsupp
, /* mountroot */
97 (int (*)(struct mount
*, struct vnode
*, struct timespec
*)) eopnotsupp
,
99 (void *)eopnotsupp
, /* vfs_suspendctl */
100 genfs_renamelock_enter
,
101 genfs_renamelock_exit
,
103 smbfs_vnodeopv_descs
,
104 0, /* vfs_refcount */
109 smbfs_modcmd(modcmd_t cmd
, void *arg
)
111 const struct sysctlnode
*smb
= NULL
;
115 case MODULE_CMD_INIT
:
116 error
= vfs_attach(&smbfs_vfsops
);
119 sysctl_createv(&smbfs_sysctl_log
, 0, NULL
, NULL
,
121 CTLTYPE_NODE
, "vfs", NULL
,
124 sysctl_createv(&smbfs_sysctl_log
, 0, NULL
, &smb
,
126 CTLTYPE_NODE
, "samba",
127 SYSCTL_DESCR("SMB/CIFS remote file system"),
129 CTL_VFS
, CTL_CREATE
, CTL_EOL
);
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
);
140 case MODULE_CMD_FINI
:
141 error
= vfs_detach(&smbfs_vfsops
);
144 sysctl_teardown(&smbfs_sysctl_log
);
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
;
161 struct smb_share
*ssp
= NULL
;
162 struct smb_cred scred
;
167 if (*data_len
< sizeof *args
)
171 if (mp
->mnt_flag
& MNT_GETARGS
) {
172 smp
= VFSTOSMBFS(mp
);
175 *args
= smp
->sm_args
;
176 *data_len
= sizeof *args
;
180 if (mp
->mnt_flag
& MNT_UPDATE
)
183 if (args
->version
!= SMBFS_VERSION
) {
184 SMBVDEBUG("mount version mismatch: kernel=%d, mount=%d\n",
185 SMBFS_VERSION
, args
->version
);
189 smb_makescred(&scred
, l
, l
->l_cred
);
190 error
= smb_dev2share(args
->dev_fd
, SMBM_EXEC
, &scred
, &ssp
);
193 smb_share_unlock(ssp
); /* keep ref, but unlock */
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
);
204 smb_share_put(ssp
, &scred
);
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
);
215 smp
->sm_hash
= hashinit(desiredvnodes
, HASH_LIST
, true,
218 mutex_init(&smp
->sm_hashlock
, MUTEX_DEFAULT
, IPL_NONE
);
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
;
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
);
242 SMBVDEBUG("smbfs_unmount: flags=%04x\n", mntflags
);
244 if (mntflags
& MNT_FORCE
)
247 if (smbfs_rootvp
->v_usecount
> 1 && (mntflags
& MNT_FORCE
) == 0)
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. */
259 error
= vflush(mp
, smbfs_rootvp
, flags
);
260 } while (error
== EBUSY
&& smp
->sm_didrele
!= 0);
266 smb_makescred(&scred
, l
, l
->l_cred
);
267 smb_share_lock(smp
->sm_share
);
268 smb_share_put(smp
->sm_share
, &scred
);
271 hashdone(smp
->sm_hash
, HASH_LIST
, smp
->sm_hashlen
);
272 mutex_destroy(&smp
->sm_hashlock
);
273 free(smp
, M_SMBFSDATA
);
278 * Get root vnode of the smbfs filesystem, and store it in sm_root.
281 smbfs_setroot(struct mount
*mp
)
283 struct smbmount
*smp
= VFSTOSMBFS(mp
);
285 struct smbfattr fattr
;
286 struct lwp
*l
= curlwp
;
287 kauth_cred_t cred
= l
->l_cred
;
288 struct smb_cred scred
;
291 KASSERT(smp
->sm_root
== NULL
);
293 smb_makescred(&scred
, l
, cred
);
294 error
= smbfs_smb_lookup(NULL
, NULL
, 0, &fattr
, &scred
);
297 error
= smbfs_nget(mp
, NULL
, "TheRooT", 7, &fattr
, &vp
);
302 * Someone might have already set sm_root while we slept
303 * in smb_lookup or malloc/getnewvnode.
308 vp
->v_vflag
|= VV_ROOT
;
309 smp
->sm_root
= VTOSMB(vp
);
311 /* Keep reference, but unlock */
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
);
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.
344 smbfs_start(struct mount
*mp
, int flags
)
346 SMBVDEBUG("flags=%04x\n", flags
);
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");
366 SMBVDEBUG0("reinit.\n");
373 pool_destroy(&smbfs_node_pool
);
374 malloc_type_detach(M_SMBNODENAME
);
375 malloc_type_detach(M_SMBFSDATA
);
377 SMBVDEBUG0("done.\n");
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
;
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
);
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
);
406 * Flush out the buffer cache
409 smbfs_sync(struct mount
*mp
, int waitfor
, kauth_cred_t cred
)
411 struct vnode
*vp
, *mvp
;
413 int error
, allerror
= 0;
415 /* Allocate a marker vnode. */
416 if ((mvp
= vnalloc(mp
)) == NULL
)
419 * Force stale buffer cache information to be flushed.
421 mutex_enter(&mntvnode_lock
);
423 for (vp
= TAILQ_FIRST(&mp
->mnt_vnodelist
); vp
; vp
= vunmark(mvp
)) {
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
))
431 mutex_enter(&vp
->v_interlock
);
434 mutex_exit(&vp
->v_interlock
);
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
);
443 mutex_exit(&mntvnode_lock
);
444 error
= vget(vp
, LK_EXCLUSIVE
| LK_NOWAIT
| LK_INTERLOCK
);
446 mutex_enter(&mntvnode_lock
);
447 if (error
== ENOENT
) {
453 error
= VOP_FSYNC(vp
, cred
,
454 waitfor
== MNT_WAIT
? FSYNC_WAIT
: 0, 0, 0);
458 mutex_enter(&mntvnode_lock
);
460 mutex_exit(&mntvnode_lock
);
465 #if __FreeBSD_version < 400009
467 * smbfs flat namespace lookup. Unsupported.
470 int smbfs_vget(struct mount
*mp
, ino_t ino
,
476 #endif /* __FreeBSD_version < 400009 */