1139776Simp/*- 2206361Sjoel * Copyright (c) 2000-2001 Boris Popov 375374Sbp * All rights reserved. 475374Sbp * 575374Sbp * Redistribution and use in source and binary forms, with or without 675374Sbp * modification, are permitted provided that the following conditions 775374Sbp * are met: 875374Sbp * 1. Redistributions of source code must retain the above copyright 975374Sbp * notice, this list of conditions and the following disclaimer. 1075374Sbp * 2. Redistributions in binary form must reproduce the above copyright 1175374Sbp * notice, this list of conditions and the following disclaimer in the 1275374Sbp * documentation and/or other materials provided with the distribution. 1375374Sbp * 1475374Sbp * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 1575374Sbp * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1675374Sbp * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 1775374Sbp * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 1875374Sbp * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 1975374Sbp * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2075374Sbp * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2175374Sbp * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2275374Sbp * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2375374Sbp * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2475374Sbp * SUCH DAMAGE. 2575374Sbp * 2675374Sbp * $FreeBSD$ 2775374Sbp */ 2875374Sbp 2975374Sbp#include <sys/param.h> 3075374Sbp#include <sys/systm.h> 3175374Sbp#include <sys/proc.h> 3275374Sbp#include <sys/bio.h> 3375374Sbp#include <sys/buf.h> 3475374Sbp#include <sys/kernel.h> 3575374Sbp#include <sys/sysctl.h> 3675374Sbp#include <sys/vnode.h> 3775374Sbp#include <sys/mount.h> 3875374Sbp#include <sys/stat.h> 3975374Sbp#include <sys/malloc.h> 4087798Ssheldonh#include <sys/module.h> 41176744Srwatson#include <sys/sx.h> 4275374Sbp 4375374Sbp 4475374Sbp#include <netsmb/smb.h> 4575374Sbp#include <netsmb/smb_conn.h> 4675374Sbp#include <netsmb/smb_subr.h> 4775374Sbp#include <netsmb/smb_dev.h> 4875374Sbp 4975374Sbp#include <fs/smbfs/smbfs.h> 5075374Sbp#include <fs/smbfs/smbfs_node.h> 5175374Sbp#include <fs/smbfs/smbfs_subr.h> 5275374Sbp 53141620Sphkstatic int smbfs_debuglevel = 0; 5475374Sbp 5575374Sbpstatic int smbfs_version = SMBFS_VERSION; 5675374Sbp 5796755StrhodesSYSCTL_NODE(_vfs, OID_AUTO, smbfs, CTLFLAG_RW, 0, "SMB/CIFS filesystem"); 5875374SbpSYSCTL_INT(_vfs_smbfs, OID_AUTO, version, CTLFLAG_RD, &smbfs_version, 0, ""); 5975374SbpSYSCTL_INT(_vfs_smbfs, OID_AUTO, debuglevel, CTLFLAG_RW, &smbfs_debuglevel, 0, ""); 6075374Sbp 61116271Sphkstatic vfs_init_t smbfs_init; 62116271Sphkstatic vfs_uninit_t smbfs_uninit; 63138490Sphkstatic vfs_cmount_t smbfs_cmount; 64138490Sphkstatic vfs_mount_t smbfs_mount; 65116271Sphkstatic vfs_root_t smbfs_root; 66116271Sphkstatic vfs_quotactl_t smbfs_quotactl; 67116271Sphkstatic vfs_statfs_t smbfs_statfs; 68116271Sphkstatic vfs_unmount_t smbfs_unmount; 6975374Sbp 7075374Sbpstatic struct vfsops smbfs_vfsops = { 71116271Sphk .vfs_init = smbfs_init, 72138490Sphk .vfs_cmount = smbfs_cmount, 73138490Sphk .vfs_mount = smbfs_mount, 74116271Sphk .vfs_quotactl = smbfs_quotactl, 75116271Sphk .vfs_root = smbfs_root, 76116271Sphk .vfs_statfs = smbfs_statfs, 77116271Sphk .vfs_sync = vfs_stdsync, 78116271Sphk .vfs_uninit = smbfs_uninit, 79116271Sphk .vfs_unmount = smbfs_unmount, 8075374Sbp}; 8175374Sbp 8275374Sbp 8375374SbpVFS_SET(smbfs_vfsops, smbfs, VFCF_NETWORK); 8475374Sbp 8575374SbpMODULE_DEPEND(smbfs, netsmb, NSMB_VERSION, NSMB_VERSION, NSMB_VERSION); 86120492SfjoeMODULE_DEPEND(smbfs, libiconv, 1, 1, 2); 8787798SsheldonhMODULE_DEPEND(smbfs, libmchain, 1, 1, 1); 8875374Sbp 8975374Sbpint smbfs_pbuf_freecnt = -1; /* start out unlimited */ 9075374Sbp 9175374Sbpstatic int 92230249Smckusicksmbfs_cmount(struct mntarg *ma, void * data, uint64_t flags) 9375374Sbp{ 94138490Sphk struct smbfs_args args; 95138490Sphk int error; 96138490Sphk 97153400Sdes error = copyin(data, &args, sizeof(struct smbfs_args)); 98138490Sphk if (error) 99138490Sphk return error; 100138490Sphk 101138490Sphk if (args.version != SMBFS_VERSION) { 102138490Sphk printf("mount version mismatch: kernel=%d, mount=%d\n", 103138490Sphk SMBFS_VERSION, args.version); 104138490Sphk return EINVAL; 105138490Sphk } 106138490Sphk ma = mount_argf(ma, "dev", "%d", args.dev); 107138490Sphk ma = mount_argb(ma, args.flags & SMBFS_MOUNT_SOFT, "nosoft"); 108138490Sphk ma = mount_argb(ma, args.flags & SMBFS_MOUNT_INTR, "nointr"); 109138490Sphk ma = mount_argb(ma, args.flags & SMBFS_MOUNT_STRONG, "nostrong"); 110138490Sphk ma = mount_argb(ma, args.flags & SMBFS_MOUNT_HAVE_NLS, "nohave_nls"); 111138490Sphk ma = mount_argb(ma, !(args.flags & SMBFS_MOUNT_NO_LONG), "nolong"); 112138490Sphk ma = mount_arg(ma, "rootpath", args.root_path, -1); 113138490Sphk ma = mount_argf(ma, "uid", "%d", args.uid); 114138490Sphk ma = mount_argf(ma, "gid", "%d", args.gid); 115138490Sphk ma = mount_argf(ma, "file_mode", "%d", args.file_mode); 116138490Sphk ma = mount_argf(ma, "dir_mode", "%d", args.dir_mode); 117138490Sphk ma = mount_argf(ma, "caseopt", "%d", args.caseopt); 118138490Sphk 119138490Sphk error = kernel_mount(ma, flags); 120138490Sphk 121138490Sphk return (error); 122138490Sphk} 123138490Sphk 124138490Sphkstatic const char *smbfs_opts[] = { 125250236Sdavide "fd", "soft", "intr", "strong", "have_nls", "long", 126138490Sphk "mountpoint", "rootpath", "uid", "gid", "file_mode", "dir_mode", 127152466Srodrigc "caseopt", "errmsg", NULL 128138490Sphk}; 129138490Sphk 130138490Sphkstatic int 131191990Sattiliosmbfs_mount(struct mount *mp) 132138490Sphk{ 13375374Sbp struct smbmount *smp = NULL; 13475374Sbp struct smb_vc *vcp; 13575374Sbp struct smb_share *ssp = NULL; 13675374Sbp struct vnode *vp; 137191990Sattilio struct thread *td; 138250236Sdavide struct smb_dev *dev; 139242386Sdavide struct smb_cred *scred; 140138490Sphk int error, v; 14175374Sbp char *pc, *pe; 14275374Sbp 143250236Sdavide dev = NULL; 144191990Sattilio td = curthread; 145137479Sphk if (mp->mnt_flag & (MNT_UPDATE | MNT_ROOTFS)) 14675374Sbp return EOPNOTSUPP; 147137479Sphk 148152466Srodrigc if (vfs_filteropt(mp->mnt_optnew, smbfs_opts)) { 149152466Srodrigc vfs_mount_error(mp, "%s", "Invalid option"); 150138490Sphk return (EINVAL); 151152466Srodrigc } 152138490Sphk 153242386Sdavide scred = smbfs_malloc_scred(); 154242386Sdavide smb_makescred(scred, td, td->td_ucred); 155250236Sdavide 156250236Sdavide /* Ask userspace of `fd`, the file descriptor of this session */ 157250236Sdavide if (1 != vfs_scanopt(mp->mnt_optnew, "fd", "%d", &v)) { 158250236Sdavide vfs_mount_error(mp, "No fd option"); 159242386Sdavide smbfs_free_scred(scred); 160138490Sphk return (EINVAL); 161152466Srodrigc } 162250236Sdavide error = smb_dev2share(v, SMBM_EXEC, scred, &ssp, &dev); 163250236Sdavide smp = malloc(sizeof(*smp), M_SMBFSDATA, M_WAITOK | M_ZERO); 16475374Sbp if (error) { 165138490Sphk printf("invalid device handle %d (%d)\n", v, error); 166250236Sdavide vfs_mount_error(mp, "invalid device handle %d %d\n", v, error); 167242386Sdavide smbfs_free_scred(scred); 168250236Sdavide free(smp, M_SMBFSDATA); 16975374Sbp return error; 17075374Sbp } 17175374Sbp vcp = SSTOVC(ssp); 172250237Sdavide smb_share_unlock(ssp); 17375374Sbp mp->mnt_stat.f_iosize = SSTOVC(ssp)->vc_txmax; 174250236Sdavide mp->mnt_data = smp; 17575374Sbp smp->sm_share = ssp; 17675374Sbp smp->sm_root = NULL; 177250236Sdavide smp->sm_dev = dev; 178138490Sphk if (1 != vfs_scanopt(mp->mnt_optnew, 179138490Sphk "caseopt", "%d", &smp->sm_caseopt)) { 180152466Srodrigc vfs_mount_error(mp, "Invalid caseopt"); 181138490Sphk error = EINVAL; 182138490Sphk goto bad; 183138490Sphk } 184138490Sphk if (1 != vfs_scanopt(mp->mnt_optnew, "uid", "%d", &v)) { 185152466Srodrigc vfs_mount_error(mp, "Invalid uid"); 186138490Sphk error = EINVAL; 187138490Sphk goto bad; 188138490Sphk } 189138490Sphk smp->sm_uid = v; 19075374Sbp 191138490Sphk if (1 != vfs_scanopt(mp->mnt_optnew, "gid", "%d", &v)) { 192152466Srodrigc vfs_mount_error(mp, "Invalid gid"); 193138490Sphk error = EINVAL; 194138490Sphk goto bad; 195138490Sphk } 196138490Sphk smp->sm_gid = v; 197138490Sphk 198138490Sphk if (1 != vfs_scanopt(mp->mnt_optnew, "file_mode", "%d", &v)) { 199152466Srodrigc vfs_mount_error(mp, "Invalid file_mode"); 200138490Sphk error = EINVAL; 201138490Sphk goto bad; 202138490Sphk } 203138490Sphk smp->sm_file_mode = (v & (S_IRWXU|S_IRWXG|S_IRWXO)) | S_IFREG; 204138490Sphk 205138490Sphk if (1 != vfs_scanopt(mp->mnt_optnew, "dir_mode", "%d", &v)) { 206152466Srodrigc vfs_mount_error(mp, "Invalid dir_mode"); 207138490Sphk error = EINVAL; 208138490Sphk goto bad; 209138490Sphk } 210138490Sphk smp->sm_dir_mode = (v & (S_IRWXU|S_IRWXG|S_IRWXO)) | S_IFDIR; 211138490Sphk 212138490Sphk vfs_flagopt(mp->mnt_optnew, 213153121Savatar "nolong", &smp->sm_flags, SMBFS_MOUNT_NO_LONG); 214138490Sphk 21575374Sbp pc = mp->mnt_stat.f_mntfromname; 21675374Sbp pe = pc + sizeof(mp->mnt_stat.f_mntfromname); 21775374Sbp bzero(pc, MNAMELEN); 21875374Sbp *pc++ = '/'; 21975374Sbp *pc++ = '/'; 220229272Sed pc = strchr(strncpy(pc, vcp->vc_username, pe - pc - 2), 0); 22175374Sbp if (pc < pe-1) { 22275374Sbp *(pc++) = '@'; 223229272Sed pc = strchr(strncpy(pc, vcp->vc_srvname, pe - pc - 2), 0); 22475374Sbp if (pc < pe - 1) { 22575374Sbp *(pc++) = '/'; 22675374Sbp strncpy(pc, ssp->ss_name, pe - pc - 2); 22775374Sbp } 22875374Sbp } 22975374Sbp vfs_getnewfsid(mp); 230191990Sattilio error = smbfs_root(mp, LK_EXCLUSIVE, &vp); 231152466Srodrigc if (error) { 232152466Srodrigc vfs_mount_error(mp, "smbfs_root error: %d", error); 23375374Sbp goto bad; 234152466Srodrigc } 235175294Sattilio VOP_UNLOCK(vp, 0); 236103936Sjeff SMBVDEBUG("root.v_usecount = %d\n", vrefcnt(vp)); 23775374Sbp 238198448Sru#ifdef DIAGNOSTIC 23975374Sbp SMBERROR("mp=%p\n", mp); 24075374Sbp#endif 241242386Sdavide smbfs_free_scred(scred); 24275374Sbp return error; 24375374Sbpbad: 24475374Sbp if (ssp) 245242386Sdavide smb_share_put(ssp, scred); 246250236Sdavide smbfs_free_scred(scred); 247250236Sdavide SMB_LOCK(); 248250236Sdavide if (error && smp->sm_dev == dev) { 249250236Sdavide smp->sm_dev = NULL; 250250236Sdavide sdp_trydestroy(dev); 251250236Sdavide } 252250236Sdavide SMB_UNLOCK(); 253250236Sdavide free(smp, M_SMBFSDATA); 254250236Sdavide return error; 25575374Sbp} 25675374Sbp 25775374Sbp/* Unmount the filesystem described by mp. */ 25875374Sbpstatic int 259191990Sattiliosmbfs_unmount(struct mount *mp, int mntflags) 26075374Sbp{ 261191990Sattilio struct thread *td; 26275374Sbp struct smbmount *smp = VFSTOSMBFS(mp); 263242386Sdavide struct smb_cred *scred; 264250236Sdavide struct smb_dev *dev; 26575374Sbp int error, flags; 26675374Sbp 26775374Sbp SMBVDEBUG("smbfs_unmount: flags=%04x\n", mntflags); 268191990Sattilio td = curthread; 26975374Sbp flags = 0; 27075374Sbp if (mntflags & MNT_FORCE) 27175374Sbp flags |= FORCECLOSE; 272107842Stjr /* 273107842Stjr * Keep trying to flush the vnode list for the mount while 274107842Stjr * some are still busy and we are making progress towards 275107842Stjr * making them not busy. This is needed because smbfs vnodes 276107842Stjr * reference their parent directory but may appear after their 277107842Stjr * parent in the list; one pass over the vnode list is not 278107842Stjr * sufficient in this case. 279107842Stjr */ 280107842Stjr do { 281107842Stjr smp->sm_didrele = 0; 282107842Stjr /* There is 1 extra root vnode reference from smbfs_mount(). */ 283132023Salfred error = vflush(mp, 1, flags, td); 284107842Stjr } while (error == EBUSY && smp->sm_didrele != 0); 28575374Sbp if (error) 28675374Sbp return error; 287242386Sdavide scred = smbfs_malloc_scred(); 288242386Sdavide smb_makescred(scred, td, td->td_ucred); 289250237Sdavide error = smb_share_lock(smp->sm_share); 290160437Sjhb if (error) 291242386Sdavide goto out; 292242386Sdavide smb_share_put(smp->sm_share, scred); 293250236Sdavide SMB_LOCK(); 294250236Sdavide dev = smp->sm_dev; 295250236Sdavide if (!dev) 296250236Sdavide panic("No private data for mount point"); 297250236Sdavide sdp_trydestroy(dev); 298172697Salfred mp->mnt_data = NULL; 299250236Sdavide SMB_UNLOCK(); 30075374Sbp free(smp, M_SMBFSDATA); 301162647Stegge MNT_ILOCK(mp); 30275374Sbp mp->mnt_flag &= ~MNT_LOCAL; 303162647Stegge MNT_IUNLOCK(mp); 304242386Sdavideout: 305242386Sdavide smbfs_free_scred(scred); 30675374Sbp return error; 30775374Sbp} 30875374Sbp 30975374Sbp/* 31075374Sbp * Return locked root vnode of a filesystem 31175374Sbp */ 31275374Sbpstatic int 313191990Sattiliosmbfs_root(struct mount *mp, int flags, struct vnode **vpp) 31475374Sbp{ 31575374Sbp struct smbmount *smp = VFSTOSMBFS(mp); 31675374Sbp struct vnode *vp; 31775374Sbp struct smbnode *np; 31875374Sbp struct smbfattr fattr; 319191990Sattilio struct thread *td; 320191990Sattilio struct ucred *cred; 321242386Sdavide struct smb_cred *scred; 32275374Sbp int error; 32375374Sbp 324191990Sattilio td = curthread; 325191990Sattilio cred = td->td_ucred; 326191990Sattilio 32775374Sbp if (smp->sm_root) { 32875374Sbp *vpp = SMBTOV(smp->sm_root); 32987194Sbp return vget(*vpp, LK_EXCLUSIVE | LK_RETRY, td); 33075374Sbp } 331242386Sdavide scred = smbfs_malloc_scred(); 332242386Sdavide smb_makescred(scred, td, cred); 333242386Sdavide error = smbfs_smb_lookup(NULL, NULL, 0, &fattr, scred); 33475374Sbp if (error) 335242386Sdavide goto out; 336243396Sdavide error = smbfs_nget(mp, NULL, NULL, 0, &fattr, &vp); 33775374Sbp if (error) 338242386Sdavide goto out; 339101308Sjeff ASSERT_VOP_LOCKED(vp, "smbfs_root"); 340101308Sjeff vp->v_vflag |= VV_ROOT; 34175374Sbp np = VTOSMB(vp); 34275374Sbp smp->sm_root = np; 34375374Sbp *vpp = vp; 344242386Sdavideout: 345242386Sdavide smbfs_free_scred(scred); 346242386Sdavide return error; 34775374Sbp} 34875374Sbp 349110533Stjr/* 350110533Stjr * Do operations associated with quotas, not supported 351110533Stjr */ 352110533Stjr/* ARGSUSED */ 353110533Stjrstatic int 354191990Sattiliosmbfs_quotactl(mp, cmd, uid, arg) 355110533Stjr struct mount *mp; 356110533Stjr int cmd; 357110533Stjr uid_t uid; 358153400Sdes void *arg; 359110533Stjr{ 360110533Stjr SMBVDEBUG("return EOPNOTSUPP\n"); 361110533Stjr return EOPNOTSUPP; 362110533Stjr} 363110533Stjr 36475374Sbp/*ARGSUSED*/ 36575374Sbpint 36675374Sbpsmbfs_init(struct vfsconf *vfsp) 36775374Sbp{ 36875374Sbp smbfs_pbuf_freecnt = nswbuf / 2 + 1; 36975374Sbp SMBVDEBUG("done.\n"); 37075374Sbp return 0; 37175374Sbp} 37275374Sbp 373110533Stjr/*ARGSUSED*/ 374110533Stjrint 375110533Stjrsmbfs_uninit(struct vfsconf *vfsp) 376110533Stjr{ 377110533Stjr 378110533Stjr SMBVDEBUG("done.\n"); 379110533Stjr return 0; 380110533Stjr} 381110533Stjr 38275374Sbp/* 38375374Sbp * smbfs_statfs call 38475374Sbp */ 38575374Sbpint 386191990Sattiliosmbfs_statfs(struct mount *mp, struct statfs *sbp) 38775374Sbp{ 388191990Sattilio struct thread *td = curthread; 38975374Sbp struct smbmount *smp = VFSTOSMBFS(mp); 39075374Sbp struct smbnode *np = smp->sm_root; 39175374Sbp struct smb_share *ssp = smp->sm_share; 392242386Sdavide struct smb_cred *scred; 393265243Sae int error; 39475374Sbp 395152466Srodrigc if (np == NULL) { 396152466Srodrigc vfs_mount_error(mp, "np == NULL"); 39775374Sbp return EINVAL; 398152466Srodrigc } 39975374Sbp 40075374Sbp sbp->f_iosize = SSTOVC(ssp)->vc_txmax; /* optimal transfer block size */ 401242386Sdavide scred = smbfs_malloc_scred(); 402242386Sdavide smb_makescred(scred, td, td->td_ucred); 403265243Sae error = smbfs_smb_statfs(ssp, sbp, scred); 404242386Sdavide smbfs_free_scred(scred); 405265243Sae return (error); 40675374Sbp} 407