import freebsd smbfs code

This commit is contained in:
deberg 2002-01-09 17:25:32 +00:00
parent c184665926
commit 18ef438300
9 changed files with 4920 additions and 0 deletions

105
sys/fs/smbfs/smbfs.h Normal file
View File

@ -0,0 +1,105 @@
/*
* Copyright (c) 2000-2001, Boris Popov
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by Boris Popov.
* 4. Neither the name of the author nor the names of any co-contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* $FreeBSD: src/sys/fs/smbfs/smbfs.h,v 1.3 2001/12/02 08:56:58 bp Exp $
*/
#ifndef _SMBFS_SMBFS_H_
#define _SMBFS_SMBFS_H_
#define SMBFS_VERMAJ 1
#define SMBFS_VERMIN 1012
#define SMBFS_VERSION (SMBFS_VERMAJ*100000 + SMBFS_VERMIN)
#define SMBFS_VFSNAME "smbfs"
/* Values for flags */
#define SMBFS_MOUNT_SOFT 0x0001
#define SMBFS_MOUNT_INTR 0x0002
#define SMBFS_MOUNT_STRONG 0x0004
#define SMBFS_MOUNT_HAVE_NLS 0x0008
#define SMBFS_MOUNT_NO_LONG 0x0010
#define SMBFS_MAXPATHCOMP 256 /* maximum number of path components */
/* Layout of the mount control block for a netware file system. */
struct smbfs_args {
int version;
int dev;
u_int flags;
char mount_point[MAXPATHLEN];
u_char root_path[512+1];
uid_t uid;
gid_t gid;
mode_t file_mode;
mode_t dir_mode;
int caseopt;
};
#ifdef _KERNEL
#ifdef MALLOC_DECLARE
MALLOC_DECLARE(M_SMBFSMNT);
#endif
struct smbnode;
struct smb_share;
struct u_cred;
struct vop_ioctl_args;
struct buf;
struct smbmount {
struct smbfs_args sm_args;
struct mount * sm_mp;
struct smbnode * sm_root;
struct ucred * sm_owner;
int sm_flags;
long sm_nextino;
struct smb_share * sm_share;
/* struct simplelock sm_npslock;*/
struct smbnode * sm_npstack[SMBFS_MAXPATHCOMP];
int sm_caseopt;
struct lock sm_hashlock;
LIST_HEAD(smbnode_hashhead, smbnode) *sm_hash;
u_long sm_hashlen;
};
#define VFSTOSMBFS(mp) ((struct smbmount *)((mp)->mnt_data))
#define SMBFSTOVFS(smp) ((struct mount *)((smp)->sm_mp))
#define VTOVFS(vp) ((vp)->v_mount)
#define VTOSMBFS(vp) (VFSTOSMBFS(VTOVFS(vp)))
int smbfs_ioctl(struct vop_ioctl_args *ap);
int smbfs_doio(struct buf *bp, struct ucred *cr, struct thread *td);
int smbfs_vinvalbuf(struct vnode *vp, int flags, struct ucred *cred,
struct thread *td, int intrflg);
#endif /* KERNEL */
#endif /* _SMBFS_SMBFS_H_ */

677
sys/fs/smbfs/smbfs_io.c Normal file
View File

@ -0,0 +1,677 @@
/*
* Copyright (c) 2000-2001, Boris Popov
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by Boris Popov.
* 4. Neither the name of the author nor the names of any co-contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* $FreeBSD: src/sys/fs/smbfs/smbfs_io.c,v 1.7 2001/12/02 08:56:58 bp Exp $
*
*/
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/resourcevar.h> /* defines plimit structure in proc struct */
#include <sys/kernel.h>
#include <sys/proc.h>
#include <sys/fcntl.h>
#include <sys/bio.h>
#include <sys/buf.h>
#include <sys/mount.h>
#include <sys/namei.h>
#include <sys/vnode.h>
#include <sys/dirent.h>
#include <sys/signalvar.h>
#include <sys/sysctl.h>
#include <sys/vmmeter.h>
#include <vm/vm.h>
#if __FreeBSD_version < 400000
#include <vm/vm_prot.h>
#endif
#include <vm/vm_page.h>
#include <vm/vm_extern.h>
#include <vm/vm_object.h>
#include <vm/vm_pager.h>
#include <vm/vnode_pager.h>
/*
#include <sys/ioccom.h>
*/
#include <netsmb/smb.h>
#include <netsmb/smb_conn.h>
#include <netsmb/smb_subr.h>
#include <fs/smbfs/smbfs.h>
#include <fs/smbfs/smbfs_node.h>
#include <fs/smbfs/smbfs_subr.h>
/*#define SMBFS_RWGENERIC*/
extern int smbfs_pbuf_freecnt;
static int smbfs_fastlookup = 1;
SYSCTL_DECL(_vfs_smbfs);
SYSCTL_INT(_vfs_smbfs, OID_AUTO, fastlookup, CTLFLAG_RW, &smbfs_fastlookup, 0, "");
#define DE_SIZE (sizeof(struct dirent))
static int
smbfs_readvdir(struct vnode *vp, struct uio *uio, struct ucred *cred)
{
struct dirent de;
struct componentname cn;
struct smb_cred scred;
struct smbfs_fctx *ctx;
struct vnode *newvp;
struct smbnode *np = VTOSMB(vp);
int error/*, *eofflag = ap->a_eofflag*/;
long offset, limit;
np = VTOSMB(vp);
SMBVDEBUG("dirname='%s'\n", np->n_name);
smb_makescred(&scred, uio->uio_td, cred);
offset = uio->uio_offset / DE_SIZE; /* offset in the directory */
limit = uio->uio_resid / DE_SIZE;
if (uio->uio_resid < DE_SIZE || uio->uio_offset < 0)
return EINVAL;
while (limit && offset < 2) {
limit--;
bzero((caddr_t)&de, DE_SIZE);
de.d_reclen = DE_SIZE;
de.d_fileno = (offset == 0) ? np->n_ino :
(np->n_parent ? np->n_parent->n_ino : 2);
if (de.d_fileno == 0)
de.d_fileno = 0x7ffffffd + offset;
de.d_namlen = offset + 1;
de.d_name[0] = '.';
de.d_name[1] = '.';
de.d_name[offset + 1] = '\0';
de.d_type = DT_DIR;
error = uiomove((caddr_t)&de, DE_SIZE, uio);
if (error)
return error;
offset++;
uio->uio_offset += DE_SIZE;
}
if (limit == 0)
return 0;
if (offset != np->n_dirofs || np->n_dirseq == NULL) {
SMBVDEBUG("Reopening search %ld:%ld\n", offset, np->n_dirofs);
if (np->n_dirseq) {
smbfs_findclose(np->n_dirseq, &scred);
np->n_dirseq = NULL;
}
np->n_dirofs = 2;
error = smbfs_findopen(np, "*", 1,
SMB_FA_SYSTEM | SMB_FA_HIDDEN | SMB_FA_DIR,
&scred, &ctx);
if (error) {
SMBVDEBUG("can not open search, error = %d", error);
return error;
}
np->n_dirseq = ctx;
} else
ctx = np->n_dirseq;
while (np->n_dirofs < offset) {
error = smbfs_findnext(ctx, offset - np->n_dirofs++, &scred);
if (error) {
smbfs_findclose(np->n_dirseq, &scred);
np->n_dirseq = NULL;
return error == ENOENT ? 0 : error;
}
}
error = 0;
for (; limit; limit--, offset++) {
error = smbfs_findnext(ctx, limit, &scred);
if (error)
break;
np->n_dirofs++;
bzero((caddr_t)&de, DE_SIZE);
de.d_reclen = DE_SIZE;
de.d_fileno = ctx->f_attr.fa_ino;
de.d_type = (ctx->f_attr.fa_attr & SMB_FA_DIR) ? DT_DIR : DT_REG;
de.d_namlen = ctx->f_nmlen;
bcopy(ctx->f_name, de.d_name, de.d_namlen);
de.d_name[de.d_namlen] = '\0';
if (smbfs_fastlookup) {
error = smbfs_nget(vp->v_mount, vp, ctx->f_name,
ctx->f_nmlen, &ctx->f_attr, &newvp);
if (!error) {
cn.cn_nameptr = de.d_name;
cn.cn_namelen = de.d_namlen;
cache_enter(vp, newvp, &cn);
vput(newvp);
}
}
error = uiomove((caddr_t)&de, DE_SIZE, uio);
if (error)
break;
}
if (error == ENOENT)
error = 0;
uio->uio_offset = offset * DE_SIZE;
return error;
}
int
smbfs_readvnode(struct vnode *vp, struct uio *uiop, struct ucred *cred)
{
struct smbmount *smp = VFSTOSMBFS(vp->v_mount);
struct smbnode *np = VTOSMB(vp);
struct thread *td;
struct vattr vattr;
struct smb_cred scred;
int error, lks;
if (vp->v_type != VREG && vp->v_type != VDIR) {
SMBFSERR("vn types other than VREG or VDIR are unsupported !\n");
return EIO;
}
if (uiop->uio_resid == 0)
return 0;
if (uiop->uio_offset < 0)
return EINVAL;
/* if (uiop->uio_offset + uiop->uio_resid > smp->nm_maxfilesize)
return EFBIG;*/
td = uiop->uio_td;
if (vp->v_type == VDIR) {
lks = LK_EXCLUSIVE;/*lockstatus(&vp->v_lock, td);*/
if (lks == LK_SHARED)
vn_lock(vp, LK_UPGRADE | LK_RETRY, td);
error = smbfs_readvdir(vp, uiop, cred);
if (lks == LK_SHARED)
vn_lock(vp, LK_DOWNGRADE | LK_RETRY, td);
return error;
}
/* biosize = SSTOCN(smp->sm_share)->sc_txmax;*/
if (np->n_flag & NMODIFIED) {
smbfs_attr_cacheremove(vp);
error = VOP_GETATTR(vp, &vattr, cred, td);
if (error)
return error;
np->n_mtime.tv_sec = vattr.va_mtime.tv_sec;
} else {
error = VOP_GETATTR(vp, &vattr, cred, td);
if (error)
return error;
if (np->n_mtime.tv_sec != vattr.va_mtime.tv_sec) {
error = smbfs_vinvalbuf(vp, V_SAVE, cred, td, 1);
if (error)
return error;
np->n_mtime.tv_sec = vattr.va_mtime.tv_sec;
}
}
smb_makescred(&scred, td, cred);
return smb_read(smp->sm_share, np->n_fid, uiop, &scred);
}
int
smbfs_writevnode(struct vnode *vp, struct uio *uiop,
struct ucred *cred, int ioflag)
{
struct smbmount *smp = VTOSMBFS(vp);
struct smbnode *np = VTOSMB(vp);
struct smb_cred scred;
struct proc *p;
struct thread *td;
int error = 0;
if (vp->v_type != VREG) {
SMBERROR("vn types other than VREG unsupported !\n");
return EIO;
}
SMBVDEBUG("ofs=%d,resid=%d\n",(int)uiop->uio_offset, uiop->uio_resid);
if (uiop->uio_offset < 0)
return EINVAL;
/* if (uiop->uio_offset + uiop->uio_resid > smp->nm_maxfilesize)
return (EFBIG);*/
td = uiop->uio_td;
p = td->td_proc;
if (ioflag & (IO_APPEND | IO_SYNC)) {
if (np->n_flag & NMODIFIED) {
smbfs_attr_cacheremove(vp);
error = smbfs_vinvalbuf(vp, V_SAVE, cred, td, 1);
if (error)
return error;
}
if (ioflag & IO_APPEND) {
#if notyet
/*
* File size can be changed by another client
*/
smbfs_attr_cacheremove(vp);
error = VOP_GETATTR(vp, &vattr, cred, td);
if (error) return (error);
#endif
uiop->uio_offset = np->n_size;
}
}
if (uiop->uio_resid == 0)
return 0;
if (p && uiop->uio_offset + uiop->uio_resid > p->p_rlimit[RLIMIT_FSIZE].rlim_cur) {
PROC_LOCK(td->td_proc);
psignal(td->td_proc, SIGXFSZ);
PROC_UNLOCK(td->td_proc);
return EFBIG;
}
smb_makescred(&scred, td, cred);
error = smb_write(smp->sm_share, np->n_fid, uiop, &scred);
SMBVDEBUG("after: ofs=%d,resid=%d\n",(int)uiop->uio_offset, uiop->uio_resid);
if (!error) {
if (uiop->uio_offset > np->n_size) {
np->n_size = uiop->uio_offset;
vnode_pager_setsize(vp, np->n_size);
}
}
return error;
}
/*
* Do an I/O operation to/from a cache block.
*/
int
smbfs_doio(struct buf *bp, struct ucred *cr, struct thread *td)
{
struct vnode *vp = bp->b_vp;
struct smbmount *smp = VFSTOSMBFS(vp->v_mount);
struct smbnode *np = VTOSMB(vp);
struct uio uio, *uiop = &uio;
struct iovec io;
struct smb_cred scred;
int error = 0;
uiop->uio_iov = &io;
uiop->uio_iovcnt = 1;
uiop->uio_segflg = UIO_SYSSPACE;
uiop->uio_td = td;
smb_makescred(&scred, td, cr);
if (bp->b_iocmd == BIO_READ) {
io.iov_len = uiop->uio_resid = bp->b_bcount;
io.iov_base = bp->b_data;
uiop->uio_rw = UIO_READ;
switch (vp->v_type) {
case VREG:
uiop->uio_offset = ((off_t)bp->b_blkno) * DEV_BSIZE;
error = smb_read(smp->sm_share, np->n_fid, uiop, &scred);
if (error)
break;
if (uiop->uio_resid) {
int left = uiop->uio_resid;
int nread = bp->b_bcount - left;
if (left > 0)
bzero((char *)bp->b_data + nread, left);
}
break;
default:
printf("smbfs_doio: type %x unexpected\n",vp->v_type);
break;
};
if (error) {
bp->b_error = error;
bp->b_ioflags |= BIO_ERROR;
}
} else { /* write */
if (((bp->b_blkno * DEV_BSIZE) + bp->b_dirtyend) > np->n_size)
bp->b_dirtyend = np->n_size - (bp->b_blkno * DEV_BSIZE);
if (bp->b_dirtyend > bp->b_dirtyoff) {
io.iov_len = uiop->uio_resid = bp->b_dirtyend - bp->b_dirtyoff;
uiop->uio_offset = ((off_t)bp->b_blkno) * DEV_BSIZE + bp->b_dirtyoff;
io.iov_base = (char *)bp->b_data + bp->b_dirtyoff;
uiop->uio_rw = UIO_WRITE;
bp->b_flags |= B_WRITEINPROG;
error = smb_write(smp->sm_share, np->n_fid, uiop, &scred);
bp->b_flags &= ~B_WRITEINPROG;
/*
* For an interrupted write, the buffer is still valid
* and the write hasn't been pushed to the server yet,
* so we can't set BIO_ERROR and report the interruption
* by setting B_EINTR. For the B_ASYNC case, B_EINTR
* is not relevant, so the rpc attempt is essentially
* a noop. For the case of a V3 write rpc not being
* committed to stable storage, the block is still
* dirty and requires either a commit rpc or another
* write rpc with iomode == NFSV3WRITE_FILESYNC before
* the block is reused. This is indicated by setting
* the B_DELWRI and B_NEEDCOMMIT flags.
*/
if (error == EINTR
|| (!error && (bp->b_flags & B_NEEDCOMMIT))) {
int s;
s = splbio();
bp->b_flags &= ~(B_INVAL|B_NOCACHE);
if ((bp->b_flags & B_ASYNC) == 0)
bp->b_flags |= B_EINTR;
if ((bp->b_flags & B_PAGING) == 0) {
bdirty(bp);
bp->b_flags &= ~B_DONE;
}
if ((bp->b_flags & B_ASYNC) == 0)
bp->b_flags |= B_EINTR;
splx(s);
} else {
if (error) {
bp->b_ioflags |= BIO_ERROR;
bp->b_error = error;
}
bp->b_dirtyoff = bp->b_dirtyend = 0;
}
} else {
bp->b_resid = 0;
bufdone(bp);
return 0;
}
}
bp->b_resid = uiop->uio_resid;
bufdone(bp);
return error;
}
/*
* Vnode op for VM getpages.
* Wish wish .... get rid from multiple IO routines
*/
int
smbfs_getpages(ap)
struct vop_getpages_args /* {
struct vnode *a_vp;
vm_page_t *a_m;
int a_count;
int a_reqpage;
vm_ooffset_t a_offset;
} */ *ap;
{
#ifdef SMBFS_RWGENERIC
return vop_stdgetpages(ap);
#else
int i, error, nextoff, size, toff, npages, count;
struct uio uio;
struct iovec iov;
vm_offset_t kva;
struct buf *bp;
struct vnode *vp;
struct thread *td;
struct ucred *cred;
struct smbmount *smp;
struct smbnode *np;
struct smb_cred scred;
vm_page_t *pages;
vp = ap->a_vp;
td = curthread; /* XXX */
cred = td->td_proc->p_ucred; /* XXX */
np = VTOSMB(vp);
smp = VFSTOSMBFS(vp->v_mount);
pages = ap->a_m;
count = ap->a_count;
if (vp->v_object == NULL) {
printf("smbfs_getpages: called with non-merged cache vnode??\n");
return VM_PAGER_ERROR;
}
smb_makescred(&scred, td, cred);
#if __FreeBSD_version >= 400000
bp = getpbuf(&smbfs_pbuf_freecnt);
#else
bp = getpbuf();
#endif
npages = btoc(count);
kva = (vm_offset_t) bp->b_data;
pmap_qenter(kva, pages, npages);
cnt.v_vnodein++;
cnt.v_vnodepgsin += count;
iov.iov_base = (caddr_t) kva;
iov.iov_len = count;
uio.uio_iov = &iov;
uio.uio_iovcnt = 1;
uio.uio_offset = IDX_TO_OFF(pages[0]->pindex);
uio.uio_resid = count;
uio.uio_segflg = UIO_SYSSPACE;
uio.uio_rw = UIO_READ;
uio.uio_td = td;
error = smb_read(smp->sm_share, np->n_fid, &uio, &scred);
pmap_qremove(kva, npages);
#if __FreeBSD_version >= 400000
relpbuf(bp, &smbfs_pbuf_freecnt);
#else
relpbuf(bp);
#endif
if (error && (uio.uio_resid == count)) {
printf("smbfs_getpages: error %d\n",error);
for (i = 0; i < npages; i++) {
if (ap->a_reqpage != i)
vm_page_free(pages[i]);
}
return VM_PAGER_ERROR;
}
size = count - uio.uio_resid;
for (i = 0, toff = 0; i < npages; i++, toff = nextoff) {
vm_page_t m;
nextoff = toff + PAGE_SIZE;
m = pages[i];
m->flags &= ~PG_ZERO;
if (nextoff <= size) {
m->valid = VM_PAGE_BITS_ALL;
vm_page_undirty(m);
} else {
int nvalid = ((size + DEV_BSIZE - 1) - toff) & ~(DEV_BSIZE - 1);
vm_page_set_validclean(m, 0, nvalid);
}
if (i != ap->a_reqpage) {
/*
* Whether or not to leave the page activated is up in
* the air, but we should put the page on a page queue
* somewhere (it already is in the object). Result:
* It appears that emperical results show that
* deactivating pages is best.
*/
/*
* Just in case someone was asking for this page we
* now tell them that it is ok to use.
*/
if (!error) {
if (m->flags & PG_WANTED)
vm_page_activate(m);
else
vm_page_deactivate(m);
vm_page_wakeup(m);
} else {
vm_page_free(m);
}
}
}
return 0;
#endif /* SMBFS_RWGENERIC */
}
/*
* Vnode op for VM putpages.
* possible bug: all IO done in sync mode
* Note that vop_close always invalidate pages before close, so it's
* not necessary to open vnode.
*/
int
smbfs_putpages(ap)
struct vop_putpages_args /* {
struct vnode *a_vp;
vm_page_t *a_m;
int a_count;
int a_sync;
int *a_rtvals;
vm_ooffset_t a_offset;
} */ *ap;
{
int error;
struct vnode *vp = ap->a_vp;
struct thread *td;
struct ucred *cred;
#ifdef SMBFS_RWGENERIC
td = curthread; /* XXX */
cred = td->td_proc->p_ucred; /* XXX */
VOP_OPEN(vp, FWRITE, cred, td);
error = vop_stdputpages(ap);
VOP_CLOSE(vp, FWRITE, cred, td);
return error;
#else
struct uio uio;
struct iovec iov;
vm_offset_t kva;
struct buf *bp;
int i, npages, count;
int *rtvals;
struct smbmount *smp;
struct smbnode *np;
struct smb_cred scred;
vm_page_t *pages;
td = curthread; /* XXX */
cred = td->td_proc->p_ucred; /* XXX */
/* VOP_OPEN(vp, FWRITE, cred, td);*/
np = VTOSMB(vp);
smp = VFSTOSMBFS(vp->v_mount);
pages = ap->a_m;
count = ap->a_count;
rtvals = ap->a_rtvals;
npages = btoc(count);
for (i = 0; i < npages; i++) {
rtvals[i] = VM_PAGER_AGAIN;
}
#if __FreeBSD_version >= 400000
bp = getpbuf(&smbfs_pbuf_freecnt);
#else
bp = getpbuf();
#endif
kva = (vm_offset_t) bp->b_data;
pmap_qenter(kva, pages, npages);
cnt.v_vnodeout++;
cnt.v_vnodepgsout += count;
iov.iov_base = (caddr_t) kva;
iov.iov_len = count;
uio.uio_iov = &iov;
uio.uio_iovcnt = 1;
uio.uio_offset = IDX_TO_OFF(pages[0]->pindex);
uio.uio_resid = count;
uio.uio_segflg = UIO_SYSSPACE;
uio.uio_rw = UIO_WRITE;
uio.uio_td = td;
SMBVDEBUG("ofs=%d,resid=%d\n",(int)uio.uio_offset, uio.uio_resid);
smb_makescred(&scred, td, cred);
error = smb_write(smp->sm_share, np->n_fid, &uio, &scred);
/* VOP_CLOSE(vp, FWRITE, cred, td);*/
SMBVDEBUG("paged write done: %d\n", error);
pmap_qremove(kva, npages);
#if __FreeBSD_version >= 400000
relpbuf(bp, &smbfs_pbuf_freecnt);
#else
relpbuf(bp);
#endif
if (!error) {
int nwritten = round_page(count - uio.uio_resid) / PAGE_SIZE;
for (i = 0; i < nwritten; i++) {
rtvals[i] = VM_PAGER_OK;
vm_page_undirty(pages[i]);
}
}
return rtvals[0];
#endif /* SMBFS_RWGENERIC */
}
/*
* Flush and invalidate all dirty buffers. If another process is already
* doing the flush, just wait for completion.
*/
int
smbfs_vinvalbuf(vp, flags, cred, td, intrflg)
struct vnode *vp;
int flags;
struct ucred *cred;
struct thread *td;
int intrflg;
{
struct smbnode *np = VTOSMB(vp);
int error = 0, slpflag, slptimeo;
if (vp->v_flag & VXLOCK)
return 0;
if (intrflg) {
slpflag = PCATCH;
slptimeo = 2 * hz;
} else {
slpflag = 0;
slptimeo = 0;
}
while (np->n_flag & NFLUSHINPROG) {
np->n_flag |= NFLUSHWANT;
error = tsleep((caddr_t)&np->n_flag, PRIBIO + 2, "smfsvinv", slptimeo);
error = smb_proc_intr(td->td_proc);
if (error == EINTR && intrflg)
return EINTR;
}
np->n_flag |= NFLUSHINPROG;
error = vinvalbuf(vp, flags, cred, td, slpflag, 0);
while (error) {
if (intrflg && (error == ERESTART || error == EINTR)) {
np->n_flag &= ~NFLUSHINPROG;
if (np->n_flag & NFLUSHWANT) {
np->n_flag &= ~NFLUSHWANT;
wakeup((caddr_t)&np->n_flag);
}
return EINTR;
}
error = vinvalbuf(vp, flags, cred, td, slpflag, 0);
}
np->n_flag &= ~(NMODIFIED | NFLUSHINPROG);
if (np->n_flag & NFLUSHWANT) {
np->n_flag &= ~NFLUSHWANT;
wakeup((caddr_t)&np->n_flag);
}
return (error);
}

416
sys/fs/smbfs/smbfs_node.c Normal file
View File

@ -0,0 +1,416 @@
/*
* Copyright (c) 2000-2001 Boris Popov
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by Boris Popov.
* 4. Neither the name of the author nor the names of any co-contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* $FreeBSD: src/sys/fs/smbfs/smbfs_node.c,v 1.5 2001/12/20 22:42:26 dillon Exp $
*/
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/kernel.h>
#include <sys/lock.h>
#include <sys/malloc.h>
#include <sys/mount.h>
#include <sys/proc.h>
#include <sys/queue.h>
#include <sys/sysctl.h>
#include <sys/time.h>
#include <sys/vnode.h>
#include <netsmb/smb.h>
#include <netsmb/smb_conn.h>
#include <netsmb/smb_subr.h>
#include <vm/vm.h>
#include <vm/vm_extern.h>
/*#include <vm/vm_page.h>
#include <vm/vm_object.h>*/
#include <fs/smbfs/smbfs.h>
#include <fs/smbfs/smbfs_node.h>
#include <fs/smbfs/smbfs_subr.h>
#define SMBFS_NOHASH(smp, hval) (&(smp)->sm_hash[(hval) & (smp)->sm_hashlen])
#define smbfs_hash_lock(smp, td) lockmgr(&smp->sm_hashlock, LK_EXCLUSIVE, NULL, td)
#define smbfs_hash_unlock(smp, td) lockmgr(&smp->sm_hashlock, LK_RELEASE, NULL, td)
extern vop_t **smbfs_vnodeop_p;
MALLOC_DEFINE(M_SMBNODE, "SMBFS node", "SMBFS vnode private part");
static MALLOC_DEFINE(M_SMBNODENAME, "SMBFS nname", "SMBFS node name");
int smbfs_hashprint(struct mount *mp);
#if 0
#ifdef SYSCTL_DECL
SYSCTL_DECL(_vfs_smbfs);
#endif
SYSCTL_PROC(_vfs_smbfs, OID_AUTO, vnprint, CTLFLAG_WR|CTLTYPE_OPAQUE,
NULL, 0, smbfs_hashprint, "S,vnlist", "vnode hash");
#endif
#define FNV_32_PRIME ((u_int32_t) 0x01000193UL)
#define FNV1_32_INIT ((u_int32_t) 33554467UL)
u_int32_t
smbfs_hash(const u_char *name, int nmlen)
{
u_int32_t v;
for (v = FNV1_32_INIT; nmlen; name++, nmlen--) {
v *= FNV_32_PRIME;
v ^= (u_int32_t)*name;
}
return v;
}
int
smbfs_hashprint(struct mount *mp)
{
struct smbmount *smp = VFSTOSMBFS(mp);
struct smbnode_hashhead *nhpp;
struct smbnode *np;
int i;
for(i = 0; i <= smp->sm_hashlen; i++) {
nhpp = &smp->sm_hash[i];
LIST_FOREACH(np, nhpp, n_hash)
vprint(NULL, SMBTOV(np));
}
return 0;
}
static char *
smbfs_name_alloc(const u_char *name, int nmlen)
{
u_char *cp;
nmlen++;
#ifdef SMBFS_NAME_DEBUG
cp = malloc(nmlen + 2 + sizeof(int), M_SMBNODENAME, M_WAITOK);
*(int*)cp = nmlen;
cp += sizeof(int);
cp[0] = 0xfc;
cp++;
bcopy(name, cp, nmlen - 1);
cp[nmlen] = 0xfe;
#else
cp = malloc(nmlen, M_SMBNODENAME, M_WAITOK);
bcopy(name, cp, nmlen - 1);
#endif
cp[nmlen - 1] = 0;
return cp;
}
static void
smbfs_name_free(u_char *name)
{
#ifdef SMBFS_NAME_DEBUG
int nmlen, slen;
u_char *cp;
cp = name;
cp--;
if (*cp != 0xfc) {
printf("First byte of name entry '%s' corrupted\n", name);
Debugger("ditto");
}
cp -= sizeof(int);
nmlen = *(int*)cp;
slen = strlen(name) + 1;
if (nmlen != slen) {
printf("Name length mismatch: was %d, now %d name '%s'\n",
nmlen, slen, name);
Debugger("ditto");
}
if (name[nmlen] != 0xfe) {
printf("Last byte of name entry '%s' corrupted\n", name);
Debugger("ditto");
}
free(cp, M_SMBNODENAME);
#else
free(name, M_SMBNODENAME);
#endif
}
static int
smbfs_node_alloc(struct mount *mp, struct vnode *dvp,
const char *name, int nmlen, struct smbfattr *fap, struct vnode **vpp)
{
struct thread *td = curthread; /* XXX */
struct smbmount *smp = VFSTOSMBFS(mp);
struct smbnode_hashhead *nhpp;
struct smbnode *np, *np2, *dnp;
struct vnode *vp;
u_long hashval;
int error;
*vpp = NULL;
if (smp->sm_root != NULL && dvp == NULL) {
SMBERROR("do not allocate root vnode twice!\n");
return EINVAL;
}
if (nmlen == 2 && bcmp(name, "..", 2) == 0) {
if (dvp == NULL)
return EINVAL;
vp = VTOSMB(dvp)->n_parent->n_vnode;
error = vget(vp, LK_EXCLUSIVE, td);
if (error == 0)
*vpp = vp;
return error;
} else if (nmlen == 1 && name[0] == '.') {
SMBERROR("do not call me with dot!\n");
return EINVAL;
}
dnp = dvp ? VTOSMB(dvp) : NULL;
if (dnp == NULL && dvp != NULL) {
vprint("smbfs_node_alloc: dead parent vnode", dvp);
return EINVAL;
}
hashval = smbfs_hash(name, nmlen);
retry:
smbfs_hash_lock(smp, td);
loop:
nhpp = SMBFS_NOHASH(smp, hashval);
LIST_FOREACH(np, nhpp, n_hash) {
vp = SMBTOV(np);
if (np->n_parent != dnp ||
np->n_nmlen != nmlen || bcmp(name, np->n_name, nmlen) != 0)
continue;
VI_LOCK(vp);
smbfs_hash_unlock(smp, td);
if (vget(vp, LK_EXCLUSIVE | LK_INTERLOCK, td) != 0)
goto retry;
*vpp = vp;
return 0;
}
smbfs_hash_unlock(smp, td);
/*
* If we don't have node attributes, then it is an explicit lookup
* for an existing vnode.
*/
if (fap == NULL)
return ENOENT;
MALLOC(np, struct smbnode *, sizeof *np, M_SMBNODE, M_WAITOK);
error = getnewvnode(VT_SMBFS, mp, smbfs_vnodeop_p, &vp);
if (error) {
FREE(np, M_SMBNODE);
return error;
}
vp->v_type = fap->fa_attr & SMB_FA_DIR ? VDIR : VREG;
bzero(np, sizeof(*np));
vp->v_data = np;
np->n_vnode = vp;
np->n_mount = VFSTOSMBFS(mp);
np->n_nmlen = nmlen;
np->n_name = smbfs_name_alloc(name, nmlen);
np->n_ino = fap->fa_ino;
if (dvp) {
np->n_parent = dnp;
if (/*vp->v_type == VDIR &&*/ (dvp->v_flag & VROOT) == 0) {
vref(dvp);
np->n_flag |= NREFPARENT;
}
} else if (vp->v_type == VREG)
SMBERROR("new vnode '%s' born without parent ?\n", np->n_name);
lockinit(&vp->v_lock, PINOD, "smbnode", VLKTIMEOUT, LK_CANRECURSE);
vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td);
smbfs_hash_lock(smp, td);
LIST_FOREACH(np2, nhpp, n_hash) {
if (np2->n_parent != dnp ||
np2->n_nmlen != nmlen || bcmp(name, np2->n_name, nmlen) != 0)
continue;
vput(vp);
/* smb_name_free(np->n_name);
FREE(np, M_SMBNODE);*/
goto loop;
}
LIST_INSERT_HEAD(nhpp, np, n_hash);
smbfs_hash_unlock(smp, td);
*vpp = vp;
return 0;
}
int
smbfs_nget(struct mount *mp, struct vnode *dvp, const char *name, int nmlen,
struct smbfattr *fap, struct vnode **vpp)
{
struct smbnode *np;
struct vnode *vp;
int error;
*vpp = NULL;
error = smbfs_node_alloc(mp, dvp, name, nmlen, fap, &vp);
if (error)
return error;
np = VTOSMB(vp);
if (fap)
smbfs_attr_cacheenter(vp, fap);
*vpp = vp;
return 0;
}
/*
* Free smbnode, and give vnode back to system
*/
int
smbfs_reclaim(ap)
struct vop_reclaim_args /* {
struct vnode *a_vp;
struct thread *a_p;
} */ *ap;
{
struct vnode *vp = ap->a_vp;
struct thread *td = ap->a_td;
struct vnode *dvp;
struct smbnode *np = VTOSMB(vp);
struct smbmount *smp = VTOSMBFS(vp);
SMBVDEBUG("%s,%d\n", np->n_name, vp->v_usecount);
smbfs_hash_lock(smp, td);
dvp = (np->n_parent && (np->n_flag & NREFPARENT)) ?
np->n_parent->n_vnode : NULL;
if (np->n_hash.le_prev)
LIST_REMOVE(np, n_hash);
cache_purge(vp);
if (smp->sm_root == np) {
SMBVDEBUG("root vnode\n");
smp->sm_root = NULL;
}
vp->v_data = NULL;
smbfs_hash_unlock(smp, td);
if (np->n_name)
smbfs_name_free(np->n_name);
FREE(np, M_SMBNODE);
if (dvp) {
VI_LOCK(dvp);
if (dvp->v_usecount >= 1) {
VI_UNLOCK(dvp);
vrele(dvp);
} else {
VI_UNLOCK(dvp);
SMBERROR("BUG: negative use count for parent!\n");
}
}
return 0;
}
int
smbfs_inactive(ap)
struct vop_inactive_args /* {
struct vnode *a_vp;
struct thread *a_td;
} */ *ap;
{
struct thread *td = ap->a_td;
struct ucred *cred = td->td_proc->p_ucred;
struct vnode *vp = ap->a_vp;
struct smbnode *np = VTOSMB(vp);
struct smb_cred scred;
int error;
SMBVDEBUG("%s: %d\n", VTOSMB(vp)->n_name, vp->v_usecount);
if (np->n_opencount) {
error = smbfs_vinvalbuf(vp, V_SAVE, cred, td, 1);
smb_makescred(&scred, td, cred);
error = smbfs_smb_close(np->n_mount->sm_share, np->n_fid,
&np->n_mtime, &scred);
np->n_opencount = 0;
}
VOP_UNLOCK(vp, 0, td);
return (0);
}
/*
* routines to maintain vnode attributes cache
* smbfs_attr_cacheenter: unpack np.i to vattr structure
*/
void
smbfs_attr_cacheenter(struct vnode *vp, struct smbfattr *fap)
{
struct smbnode *np = VTOSMB(vp);
if (vp->v_type == VREG) {
if (np->n_size != fap->fa_size) {
np->n_size = fap->fa_size;
vnode_pager_setsize(vp, np->n_size);
}
} else if (vp->v_type == VDIR) {
np->n_size = 16384; /* should be a better way ... */
} else
return;
np->n_mtime = fap->fa_mtime;
np->n_dosattr = fap->fa_attr;
np->n_attrage = time_second;
return;
}
int
smbfs_attr_cachelookup(struct vnode *vp, struct vattr *va)
{
struct smbnode *np = VTOSMB(vp);
struct smbmount *smp = VTOSMBFS(vp);
int diff;
diff = time_second - np->n_attrage;
if (diff > 2) /* XXX should be configurable */
return ENOENT;
va->va_type = vp->v_type; /* vnode type (for create) */
if (vp->v_type == VREG) {
va->va_mode = smp->sm_args.file_mode; /* files access mode and type */
} else if (vp->v_type == VDIR) {
va->va_mode = smp->sm_args.dir_mode; /* files access mode and type */
} else
return EINVAL;
va->va_size = np->n_size;
va->va_nlink = 1; /* number of references to file */
va->va_uid = smp->sm_args.uid; /* owner user id */
va->va_gid = smp->sm_args.gid; /* owner group id */
va->va_fsid = vp->v_mount->mnt_stat.f_fsid.val[0];
va->va_fileid = np->n_ino; /* file id */
if (va->va_fileid == 0)
va->va_fileid = 2;
va->va_blocksize = SSTOVC(smp->sm_share)->vc_txmax;
va->va_mtime = np->n_mtime;
va->va_atime = va->va_ctime = va->va_mtime; /* time file changed */
va->va_gen = VNOVAL; /* generation number of file */
va->va_flags = 0; /* flags defined for file */
va->va_rdev = VNOVAL; /* device the special file represents */
va->va_bytes = va->va_size; /* bytes of disk space held by file */
va->va_filerev = 0; /* file modification number */
va->va_vaflags = 0; /* operations flags */
return 0;
}

100
sys/fs/smbfs/smbfs_node.h Normal file
View File

@ -0,0 +1,100 @@
/*
* Copyright (c) 2000-2001, Boris Popov
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by Boris Popov.
* 4. Neither the name of the author nor the names of any co-contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* $FreeBSD: src/sys/fs/smbfs/smbfs_node.h,v 1.1 2001/04/10 07:59:05 bp Exp $
*/
#ifndef _FS_SMBFS_NODE_H_
#define _FS_SMBFS_NODE_H_
#define SMBFS_ROOT_INO 2 /* just like in UFS */
/* Bits for smbnode.n_flag */
#define NFLUSHINPROG 0x0001
#define NFLUSHWANT 0x0002 /* they should gone ... */
#define NMODIFIED 0x0004 /* bogus, until async IO implemented */
/*efine NNEW 0x0008*//* smb/vnode has been allocated */
#define NREFPARENT 0x0010 /* node holds parent from recycling */
struct smbfs_fctx;
struct smbnode {
#ifndef FB_CURRENT
struct lock n_lock; /* smbnode lock. (mbf) */
#endif
int n_flag;
struct smbnode * n_parent;
struct vnode * n_vnode;
struct smbmount * n_mount;
time_t n_attrage; /* attributes cache time */
/* time_t n_ctime;*/
struct timespec n_mtime; /* modify time */
struct timespec n_atime; /* last access time */
u_quad_t n_size;
long n_ino;
int n_dosattr;
int n_opencount;
u_int16_t n_fid; /* file handle */
int n_rwstate; /* granted access mode */
u_char n_nmlen;
u_char * n_name;
struct smbfs_fctx * n_dirseq; /* ff context */
long n_dirofs; /* last ff offset */
struct lockf * n_lockf; /* Locking records of file */
LIST_ENTRY(smbnode) n_hash;
};
#define VTOSMB(vp) ((struct smbnode *)(vp)->v_data)
#define SMBTOV(np) ((struct vnode *)(np)->n_vnode)
struct vop_getpages_args;
struct vop_inactive_args;
struct vop_putpages_args;
struct vop_reclaim_args;
struct ucred;
struct uio;
struct smbfattr;
int smbfs_inactive(struct vop_inactive_args *);
int smbfs_reclaim(struct vop_reclaim_args *);
int smbfs_nget(struct mount *mp, struct vnode *dvp, const char *name, int nmlen,
struct smbfattr *fap, struct vnode **vpp);
u_int32_t smbfs_hash(const u_char *name, int nmlen);
int smbfs_getpages(struct vop_getpages_args *);
int smbfs_putpages(struct vop_putpages_args *);
int smbfs_readvnode(struct vnode *vp, struct uio *uiop, struct ucred *cred);
int smbfs_writevnode(struct vnode *vp, struct uio *uiop, struct ucred *cred, int ioflag);
void smbfs_attr_cacheenter(struct vnode *vp, struct smbfattr *fap);
int smbfs_attr_cachelookup(struct vnode *vp ,struct vattr *va);
#define smbfs_attr_cacheremove(vp) VTOSMB(vp)->n_attrage = 0
#endif /* _FS_SMBFS_NODE_H_ */

1273
sys/fs/smbfs/smbfs_smb.c Normal file

File diff suppressed because it is too large Load Diff

326
sys/fs/smbfs/smbfs_subr.c Normal file
View File

@ -0,0 +1,326 @@
/*
* Copyright (c) 2000-2001, Boris Popov
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by Boris Popov.
* 4. Neither the name of the author nor the names of any co-contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* $FreeBSD: src/sys/fs/smbfs/smbfs_subr.c,v 1.1 2001/04/10 07:59:05 bp Exp $
*/
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/kernel.h>
#include <sys/malloc.h>
#include <machine/clock.h>
#include <sys/time.h>
#include <sys/vnode.h>
#include <sys/sysctl.h>
#include <sys/iconv.h>
#include <netsmb/smb.h>
#include <netsmb/smb_conn.h>
#include <netsmb/smb_subr.h>
#include <netsmb/smb_rq.h>
#include <netsmb/smb_dev.h>
#include <fs/smbfs/smbfs.h>
#include <fs/smbfs/smbfs_node.h>
#include <fs/smbfs/smbfs_subr.h>
MALLOC_DEFINE(M_SMBFSDATA, "SMBFS data", "SMBFS private data");
/*
* Time & date conversion routines taken from msdosfs. Although leap
* year calculation is bogus, it's sufficient before 2100 :)
*/
/*
* This is the format of the contents of the deTime field in the direntry
* structure.
* We don't use bitfields because we don't know how compilers for
* arbitrary machines will lay them out.
*/
#define DT_2SECONDS_MASK 0x1F /* seconds divided by 2 */
#define DT_2SECONDS_SHIFT 0
#define DT_MINUTES_MASK 0x7E0 /* minutes */
#define DT_MINUTES_SHIFT 5
#define DT_HOURS_MASK 0xF800 /* hours */
#define DT_HOURS_SHIFT 11
/*
* This is the format of the contents of the deDate field in the direntry
* structure.
*/
#define DD_DAY_MASK 0x1F /* day of month */
#define DD_DAY_SHIFT 0
#define DD_MONTH_MASK 0x1E0 /* month */
#define DD_MONTH_SHIFT 5
#define DD_YEAR_MASK 0xFE00 /* year - 1980 */
#define DD_YEAR_SHIFT 9
/*
* Total number of days that have passed for each month in a regular year.
*/
static u_short regyear[] = {
31, 59, 90, 120, 151, 181,
212, 243, 273, 304, 334, 365
};
/*
* Total number of days that have passed for each month in a leap year.
*/
static u_short leapyear[] = {
31, 60, 91, 121, 152, 182,
213, 244, 274, 305, 335, 366
};
/*
* Variables used to remember parts of the last time conversion. Maybe we
* can avoid a full conversion.
*/
static u_long lasttime;
static u_long lastday;
static u_short lastddate;
static u_short lastdtime;
void
smb_time_local2server(struct timespec *tsp, int tzoff, u_long *seconds)
{
*seconds = tsp->tv_sec - tzoff * 60 /*- tz.tz_minuteswest * 60 -
(wall_cmos_clock ? adjkerntz : 0)*/;
}
void
smb_time_server2local(u_long seconds, int tzoff, struct timespec *tsp)
{
tsp->tv_sec = seconds + tzoff * 60;
/*+ tz.tz_minuteswest * 60 + (wall_cmos_clock ? adjkerntz : 0)*/;
}
/*
* Number of seconds between 1970 and 1601 year
*/
int64_t DIFF1970TO1601 = 11644473600ULL;
/*
* Time from server comes as UTC, so no need to use tz
*/
void
smb_time_NT2local(int64_t nsec, int tzoff, struct timespec *tsp)
{
smb_time_server2local(nsec / 10000000 - DIFF1970TO1601, 0, tsp);
}
void
smb_time_local2NT(struct timespec *tsp, int tzoff, int64_t *nsec)
{
u_long seconds;
smb_time_local2server(tsp, 0, &seconds);
*nsec = (((int64_t)(seconds) & ~1) + DIFF1970TO1601) * (int64_t)10000000;
}
void
smb_time_unix2dos(struct timespec *tsp, int tzoff, u_int16_t *ddp,
u_int16_t *dtp, u_int8_t *dhp)
{
u_long t, days, year, month, inc;
u_short *months;
/*
* If the time from the last conversion is the same as now, then
* skip the computations and use the saved result.
*/
smb_time_local2server(tsp, tzoff, &t);
t &= ~1;
if (lasttime != t) {
lasttime = t;
lastdtime = (((t / 2) % 30) << DT_2SECONDS_SHIFT)
+ (((t / 60) % 60) << DT_MINUTES_SHIFT)
+ (((t / 3600) % 24) << DT_HOURS_SHIFT);
/*
* If the number of days since 1970 is the same as the last
* time we did the computation then skip all this leap year
* and month stuff.
*/
days = t / (24 * 60 * 60);
if (days != lastday) {
lastday = days;
for (year = 1970;; year++) {
inc = year & 0x03 ? 365 : 366;
if (days < inc)
break;
days -= inc;
}
months = year & 0x03 ? regyear : leapyear;
for (month = 0; days >= months[month]; month++)
;
if (month > 0)
days -= months[month - 1];
lastddate = ((days + 1) << DD_DAY_SHIFT)
+ ((month + 1) << DD_MONTH_SHIFT);
/*
* Remember dos's idea of time is relative to 1980.
* unix's is relative to 1970. If somehow we get a
* time before 1980 then don't give totally crazy
* results.
*/
if (year > 1980)
lastddate += (year - 1980) << DD_YEAR_SHIFT;
}
}
if (dtp)
*dtp = lastdtime;
if (dhp)
*dhp = (tsp->tv_sec & 1) * 100 + tsp->tv_nsec / 10000000;
*ddp = lastddate;
}
/*
* The number of seconds between Jan 1, 1970 and Jan 1, 1980. In that
* interval there were 8 regular years and 2 leap years.
*/
#define SECONDSTO1980 (((8 * 365) + (2 * 366)) * (24 * 60 * 60))
static u_short lastdosdate;
static u_long lastseconds;
void
smb_dos2unixtime(u_int dd, u_int dt, u_int dh, int tzoff,
struct timespec *tsp)
{
u_long seconds;
u_long month;
u_long year;
u_long days;
u_short *months;
if (dd == 0) {
tsp->tv_sec = 0;
tsp->tv_nsec = 0;
return;
}
seconds = (((dt & DT_2SECONDS_MASK) >> DT_2SECONDS_SHIFT) << 1)
+ ((dt & DT_MINUTES_MASK) >> DT_MINUTES_SHIFT) * 60
+ ((dt & DT_HOURS_MASK) >> DT_HOURS_SHIFT) * 3600
+ dh / 100;
/*
* If the year, month, and day from the last conversion are the
* same then use the saved value.
*/
if (lastdosdate != dd) {
lastdosdate = dd;
days = 0;
year = (dd & DD_YEAR_MASK) >> DD_YEAR_SHIFT;
days = year * 365;
days += year / 4 + 1; /* add in leap days */
if ((year & 0x03) == 0)
days--; /* if year is a leap year */
months = year & 0x03 ? regyear : leapyear;
month = (dd & DD_MONTH_MASK) >> DD_MONTH_SHIFT;
if (month < 1 || month > 12) {
month = 1;
}
if (month > 1)
days += months[month - 2];
days += ((dd & DD_DAY_MASK) >> DD_DAY_SHIFT) - 1;
lastseconds = (days * 24 * 60 * 60) + SECONDSTO1980;
}
smb_time_server2local(seconds + lastseconds, tzoff, tsp);
tsp->tv_nsec = (dh % 100) * 10000000;
}
static int
smb_fphelp(struct mbchain *mbp, struct smb_vc *vcp, struct smbnode *np,
int caseopt)
{
struct smbmount *smp= np->n_mount;
struct smbnode **npp = smp->sm_npstack;
int i, error = 0;
/* simple_lock(&smp->sm_npslock);*/
i = 0;
while (np->n_parent) {
if (i++ == SMBFS_MAXPATHCOMP) {
/* simple_unlock(&smp->sm_npslock);*/
return ENAMETOOLONG;
}
*npp++ = np;
np = np->n_parent;
}
/* if (i == 0)
return smb_put_dmem(mbp, vcp, "\\", 2, caseopt);*/
while (i--) {
np = *--npp;
error = mb_put_uint8(mbp, '\\');
if (error)
break;
error = smb_put_dmem(mbp, vcp, np->n_name, np->n_nmlen, caseopt);
if (error)
break;
}
/* simple_unlock(&smp->sm_npslock);*/
return error;
}
int
smbfs_fullpath(struct mbchain *mbp, struct smb_vc *vcp, struct smbnode *dnp,
const char *name, int nmlen)
{
int caseopt = SMB_CS_NONE;
int error;
if (SMB_DIALECT(vcp) < SMB_DIALECT_LANMAN1_0)
caseopt |= SMB_CS_UPPER;
if (dnp != NULL) {
error = smb_fphelp(mbp, vcp, dnp, caseopt);
if (error)
return error;
}
if (name) {
error = mb_put_uint8(mbp, '\\');
if (error)
return error;
error = smb_put_dmem(mbp, vcp, name, nmlen, caseopt);
if (error)
return error;
}
error = mb_put_uint8(mbp, 0);
return error;
}
int
smbfs_fname_tolocal(struct smb_vc *vcp, char *name, int nmlen, int caseopt)
{
/* if (caseopt & SMB_CS_UPPER)
iconv_convmem(vcp->vc_toupper, name, name, nmlen);
else if (caseopt & SMB_CS_LOWER)
iconv_convmem(vcp->vc_tolower, name, name, nmlen);*/
if (vcp->vc_tolocal)
iconv_convmem(vcp->vc_tolocal, name, name, nmlen);
return 0;
}

187
sys/fs/smbfs/smbfs_subr.h Normal file
View File

@ -0,0 +1,187 @@
/*
* Copyright (c) 2000-2001, Boris Popov
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by Boris Popov.
* 4. Neither the name of the author nor the names of any co-contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* $FreeBSD: src/sys/fs/smbfs/smbfs_subr.h,v 1.2 2001/12/10 08:09:46 obrien Exp $
*/
#ifndef _FS_SMBFS_SMBFS_SUBR_H_
#define _FS_SMBFS_SMBFS_SUBR_H_
#ifdef MALLOC_DECLARE
MALLOC_DECLARE(M_SMBFSDATA);
#endif
#define SMBFSERR(format, args...) printf("%s: "format, __func__ ,## args)
#ifdef SMB_VNODE_DEBUG
#define SMBVDEBUG(format, args...) printf("%s: "format, __func__ ,## args)
#else
#define SMBVDEBUG(format, args...)
#endif
/*
* Possible lock commands
*/
#define SMB_LOCK_EXCL 0
#define SMB_LOCK_SHARED 1
#define SMB_LOCK_RELEASE 2
struct smbmount;
struct proc;
struct timespec;
struct ucred;
struct vattr;
struct vnode;
struct statfs;
struct smbfattr {
int fa_attr;
int64_t fa_size;
struct timespec fa_atime;
struct timespec fa_ctime;
struct timespec fa_mtime;
long fa_ino;
};
/*
* Context to perform findfirst/findnext/findclose operations
*/
#define SMBFS_RDD_FINDFIRST 0x01
#define SMBFS_RDD_EOF 0x02
#define SMBFS_RDD_FINDSINGLE 0x04
#define SMBFS_RDD_USESEARCH 0x08
#define SMBFS_RDD_NOCLOSE 0x10
#define SMBFS_RDD_GOTRNAME 0x1000
/*
* Search context supplied by server
*/
#define SMB_SKEYLEN 21 /* search context */
#define SMB_DENTRYLEN (SMB_SKEYLEN + 22) /* entire entry */
struct smbfs_fctx {
/*
* Setable values
*/
int f_flags; /* SMBFS_RDD_ */
/*
* Return values
*/
struct smbfattr f_attr; /* current attributes */
char * f_name; /* current file name */
int f_nmlen; /* name len */
/*
* Internal variables
*/
int f_limit; /* maximum number of entries */
int f_attrmask; /* SMB_FA_ */
int f_wclen;
const char * f_wildcard;
struct smbnode* f_dnp;
struct smb_cred*f_scred;
struct smb_share *f_ssp;
union {
struct smb_rq * uf_rq;
struct smb_t2rq * uf_t2;
} f_urq;
int f_left; /* entries left */
int f_ecnt; /* entries left in the current reponse */
int f_eofs; /* entry offset in the parameter block */
u_char f_skey[SMB_SKEYLEN]; /* server side search context */
u_char f_fname[8 + 1 + 3 + 1]; /* common case for 8.3 filenames */
u_int16_t f_Sid;
u_int16_t f_infolevel;
int f_rnamelen;
char * f_rname; /* resume name/key */
int f_rnameofs;
};
#define f_rq f_urq.uf_rq
#define f_t2 f_urq.uf_t2
extern int smbfs_debuglevel;
/*
* smb level
*/
int smbfs_smb_lock(struct smbnode *np, int op, caddr_t id,
off_t start, off_t end, struct smb_cred *scred);
int smbfs_smb_statfs2(struct smb_share *ssp, struct statfs *sbp,
struct smb_cred *scred);
int smbfs_smb_statfs(struct smb_share *ssp, struct statfs *sbp,
struct smb_cred *scred);
int smbfs_smb_setfsize(struct smbnode *np, int newsize, struct smb_cred *scred);
int smbfs_smb_setpattr(struct smbnode *np, u_int16_t attr,
struct timespec *mtime, struct smb_cred *scred);
int smbfs_smb_setptime2(struct smbnode *np, struct timespec *mtime,
struct timespec *atime, int attr, struct smb_cred *scred);
int smbfs_smb_setpattrNT(struct smbnode *np, u_int16_t attr,
struct timespec *mtime, struct timespec *atime, struct smb_cred *scred);
int smbfs_smb_setftime(struct smbnode *np, struct timespec *mtime,
struct timespec *atime, struct smb_cred *scred);
int smbfs_smb_setfattrNT(struct smbnode *np, u_int16_t attr,
struct timespec *mtime, struct timespec *atime, struct smb_cred *scred);
int smbfs_smb_open(struct smbnode *np, int accmode, struct smb_cred *scred);
int smbfs_smb_close(struct smb_share *ssp, u_int16_t fid,
struct timespec *mtime, struct smb_cred *scred);
int smbfs_smb_create(struct smbnode *dnp, const char *name, int len,
struct smb_cred *scred);
int smbfs_smb_delete(struct smbnode *np, struct smb_cred *scred);
int smbfs_smb_rename(struct smbnode *src, struct smbnode *tdnp,
const char *tname, int tnmlen, struct smb_cred *scred);
int smbfs_smb_move(struct smbnode *src, struct smbnode *tdnp,
const char *tname, int tnmlen, u_int16_t flags, struct smb_cred *scred);
int smbfs_smb_mkdir(struct smbnode *dnp, const char *name, int len,
struct smb_cred *scred);
int smbfs_smb_rmdir(struct smbnode *np, struct smb_cred *scred);
int smbfs_findopen(struct smbnode *dnp, const char *wildcard, int wclen,
int attr, struct smb_cred *scred, struct smbfs_fctx **ctxpp);
int smbfs_findnext(struct smbfs_fctx *ctx, int limit, struct smb_cred *scred);
int smbfs_findclose(struct smbfs_fctx *ctx, struct smb_cred *scred);
int smbfs_fullpath(struct mbchain *mbp, struct smb_vc *vcp,
struct smbnode *dnp, const char *name, int nmlen);
int smbfs_smb_lookup(struct smbnode *dnp, const char *name, int nmlen,
struct smbfattr *fap, struct smb_cred *scred);
int smbfs_fname_tolocal(struct smb_vc *vcp, char *name, int nmlen, int caseopt);
void smb_time_local2server(struct timespec *tsp, int tzoff, u_long *seconds);
void smb_time_server2local(u_long seconds, int tzoff, struct timespec *tsp);
void smb_time_NT2local(int64_t nsec, int tzoff, struct timespec *tsp);
void smb_time_local2NT(struct timespec *tsp, int tzoff, int64_t *nsec);
void smb_time_unix2dos(struct timespec *tsp, int tzoff, u_int16_t *ddp,
u_int16_t *dtp, u_int8_t *dhp);
void smb_dos2unixtime (u_int dd, u_int dt, u_int dh, int tzoff, struct timespec *tsp);
#endif /* !_FS_SMBFS_SMBFS_SUBR_H_ */

502
sys/fs/smbfs/smbfs_vfsops.c Normal file
View File

@ -0,0 +1,502 @@
/*
* Copyright (c) 2000-2001, Boris Popov
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by Boris Popov.
* 4. Neither the name of the author nor the names of any co-contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* $FreeBSD: src/sys/fs/smbfs/smbfs_vfsops.c,v 1.5 2001/12/13 13:08:34 sheldonh Exp $
*/
#include "opt_netsmb.h"
#ifndef NETSMB
#error "SMBFS requires option NETSMB"
#endif
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/proc.h>
#include <sys/bio.h>
#include <sys/buf.h>
#include <sys/kernel.h>
#include <sys/sysctl.h>
#include <sys/vnode.h>
#include <sys/mount.h>
#include <sys/stat.h>
#include <sys/malloc.h>
#include <sys/module.h>
#include <netsmb/smb.h>
#include <netsmb/smb_conn.h>
#include <netsmb/smb_subr.h>
#include <netsmb/smb_dev.h>
#include <fs/smbfs/smbfs.h>
#include <fs/smbfs/smbfs_node.h>
#include <fs/smbfs/smbfs_subr.h>
int smbfs_debuglevel = 0;
static int smbfs_version = SMBFS_VERSION;
#ifdef SMBFS_USEZONE
#include <vm/vm.h>
#include <vm/vm_extern.h>
#include <vm/vm_zone.h>
vm_zone_t smbfsmount_zone;
#endif
SYSCTL_NODE(_vfs, OID_AUTO, smbfs, CTLFLAG_RW, 0, "SMB/CIFS file system");
SYSCTL_INT(_vfs_smbfs, OID_AUTO, version, CTLFLAG_RD, &smbfs_version, 0, "");
SYSCTL_INT(_vfs_smbfs, OID_AUTO, debuglevel, CTLFLAG_RW, &smbfs_debuglevel, 0, "");
static MALLOC_DEFINE(M_SMBFSHASH, "SMBFS hash", "SMBFS hash table");
static int smbfs_mount(struct mount *, char *, caddr_t,
struct nameidata *, struct thread *);
static int smbfs_quotactl(struct mount *, int, uid_t, caddr_t, struct thread *);
static int smbfs_root(struct mount *, struct vnode **);
static int smbfs_start(struct mount *, int, struct thread *);
static int smbfs_statfs(struct mount *, struct statfs *, struct thread *);
static int smbfs_sync(struct mount *, int, struct ucred *, struct thread *);
static int smbfs_unmount(struct mount *, int, struct thread *);
static int smbfs_init(struct vfsconf *vfsp);
static int smbfs_uninit(struct vfsconf *vfsp);
#if __FreeBSD_version < 400009
static int smbfs_vget(struct mount *mp, ino_t ino, struct vnode **vpp);
static int smbfs_fhtovp(struct mount *, struct fid *,
struct sockaddr *, struct vnode **, int *,
struct ucred **);
static int smbfs_vptofh(struct vnode *, struct fid *);
#endif
static struct vfsops smbfs_vfsops = {
smbfs_mount,
smbfs_start,
smbfs_unmount,
smbfs_root,
smbfs_quotactl,
smbfs_statfs,
smbfs_sync,
#if __FreeBSD_version > 400008
vfs_stdvget,
vfs_stdfhtovp, /* shouldn't happen */
vfs_stdcheckexp,
vfs_stdvptofh, /* shouldn't happen */
#else
smbfs_vget,
smbfs_fhtovp,
smbfs_vptofh,
#endif
smbfs_init,
smbfs_uninit,
#ifndef FB_RELENG3
vfs_stdextattrctl,
#else
#define M_USE_RESERVE M_KERNEL
&sysctl___vfs_smbfs
#endif
};
VFS_SET(smbfs_vfsops, smbfs, VFCF_NETWORK);
MODULE_DEPEND(smbfs, netsmb, NSMB_VERSION, NSMB_VERSION, NSMB_VERSION);
MODULE_DEPEND(smbfs, libiconv, 1, 1, 1);
MODULE_DEPEND(smbfs, libmchain, 1, 1, 1);
int smbfs_pbuf_freecnt = -1; /* start out unlimited */
static int
smbfs_mount(struct mount *mp, char *path, caddr_t data,
struct nameidata *ndp, struct thread *td)
{
struct smbfs_args args; /* will hold data from mount request */
struct smbmount *smp = NULL;
struct smb_vc *vcp;
struct smb_share *ssp = NULL;
struct vnode *vp;
struct smb_cred scred;
#ifndef FB_CURRENT
size_t size;
#endif
int error;
char *pc, *pe;
if (data == NULL) {
printf("missing data argument\n");
return EINVAL;
}
if (mp->mnt_flag & MNT_UPDATE) {
printf("MNT_UPDATE not implemented");
return EOPNOTSUPP;
}
error = copyin(data, (caddr_t)&args, sizeof(struct smbfs_args));
if (error)
return error;
if (args.version != SMBFS_VERSION) {
printf("mount version mismatch: kernel=%d, mount=%d\n",
SMBFS_VERSION, args.version);
return EINVAL;
}
smb_makescred(&scred, td, td->td_proc->p_ucred);
error = smb_dev2share(args.dev, SMBM_EXEC, &scred, &ssp);
if (error) {
printf("invalid device handle %d (%d)\n", args.dev, error);
return error;
}
vcp = SSTOVC(ssp);
smb_share_unlock(ssp, 0, td);
mp->mnt_stat.f_iosize = SSTOVC(ssp)->vc_txmax;
#ifdef SMBFS_USEZONE
smp = zalloc(smbfsmount_zone);
#else
MALLOC(smp, struct smbmount*, sizeof(*smp), M_SMBFSDATA, M_USE_RESERVE);
#endif
if (smp == NULL) {
printf("could not alloc smbmount\n");
error = ENOMEM;
goto bad;
}
bzero(smp, sizeof(*smp));
mp->mnt_data = (qaddr_t)smp;
smp->sm_hash = hashinit(desiredvnodes, M_SMBFSHASH, &smp->sm_hashlen);
if (smp->sm_hash == NULL)
goto bad;
lockinit(&smp->sm_hashlock, PVFS, "smbfsh", 0, 0);
smp->sm_share = ssp;
smp->sm_root = NULL;
smp->sm_args = args;
smp->sm_caseopt = args.caseopt;
smp->sm_args.file_mode = (smp->sm_args.file_mode &
(S_IRWXU|S_IRWXG|S_IRWXO)) | S_IFREG;
smp->sm_args.dir_mode = (smp->sm_args.dir_mode &
(S_IRWXU|S_IRWXG|S_IRWXO)) | S_IFDIR;
/* simple_lock_init(&smp->sm_npslock);*/
#ifndef FB_CURRENT
error = copyinstr(path, mp->mnt_stat.f_mntonname, MNAMELEN - 1, &size);
if (error)
goto bad;
bzero(mp->mnt_stat.f_mntonname + size, MNAMELEN - size);
#endif
pc = mp->mnt_stat.f_mntfromname;
pe = pc + sizeof(mp->mnt_stat.f_mntfromname);
bzero(pc, MNAMELEN);
*pc++ = '/';
*pc++ = '/';
pc=index(strncpy(pc, vcp->vc_username, pe - pc - 2), 0);
if (pc < pe-1) {
*(pc++) = '@';
pc = index(strncpy(pc, vcp->vc_srvname, pe - pc - 2), 0);
if (pc < pe - 1) {
*(pc++) = '/';
strncpy(pc, ssp->ss_name, pe - pc - 2);
}
}
/* protect against invalid mount points */
smp->sm_args.mount_point[sizeof(smp->sm_args.mount_point) - 1] = '\0';
vfs_getnewfsid(mp);
error = smbfs_root(mp, &vp);
if (error)
goto bad;
VOP_UNLOCK(vp, 0, td);
SMBVDEBUG("root.v_usecount = %d\n", vp->v_usecount);
#ifdef DIAGNOSTICS
SMBERROR("mp=%p\n", mp);
#endif
return error;
bad:
if (smp) {
if (smp->sm_hash)
free(smp->sm_hash, M_SMBFSHASH);
lockdestroy(&smp->sm_hashlock);
#ifdef SMBFS_USEZONE
zfree(smbfsmount_zone, smp);
#else
free(smp, M_SMBFSDATA);
#endif
}
if (ssp)
smb_share_put(ssp, &scred);
return error;
}
/* Unmount the filesystem described by mp. */
static int
smbfs_unmount(struct mount *mp, int mntflags, struct thread *td)
{
struct smbmount *smp = VFSTOSMBFS(mp);
struct smb_cred scred;
int error, flags;
SMBVDEBUG("smbfs_unmount: flags=%04x\n", mntflags);
flags = 0;
if (mntflags & MNT_FORCE)
flags |= FORCECLOSE;
/* There is 1 extra root vnode reference from smbfs_mount(). */
error = vflush(mp, 1, flags);
if (error)
return error;
smb_makescred(&scred, td, td->td_proc->p_ucred);
smb_share_put(smp->sm_share, &scred);
mp->mnt_data = (qaddr_t)0;
if (smp->sm_hash)
free(smp->sm_hash, M_SMBFSHASH);
lockdestroy(&smp->sm_hashlock);
#ifdef SMBFS_USEZONE
zfree(smbfsmount_zone, smp);
#else
free(smp, M_SMBFSDATA);
#endif
mp->mnt_flag &= ~MNT_LOCAL;
return error;
}
/*
* Return locked root vnode of a filesystem
*/
static int
smbfs_root(struct mount *mp, struct vnode **vpp)
{
struct smbmount *smp = VFSTOSMBFS(mp);
struct vnode *vp;
struct smbnode *np;
struct smbfattr fattr;
struct thread *td = curthread;
struct ucred *cred = td->td_proc->p_ucred;
struct smb_cred scred;
int error;
if (smp == NULL) {
SMBERROR("smp == NULL (bug in umount)\n");
return EINVAL;
}
if (smp->sm_root) {
*vpp = SMBTOV(smp->sm_root);
return vget(*vpp, LK_EXCLUSIVE | LK_RETRY, td);
}
smb_makescred(&scred, td, cred);
error = smbfs_smb_lookup(NULL, NULL, 0, &fattr, &scred);
if (error)
return error;
error = smbfs_nget(mp, NULL, "TheRooT", 7, &fattr, &vp);
if (error)
return error;
vp->v_flag |= VROOT;
np = VTOSMB(vp);
smp->sm_root = np;
*vpp = vp;
return 0;
}
/*
* Vfs start routine, a no-op.
*/
/* ARGSUSED */
static int
smbfs_start(mp, flags, td)
struct mount *mp;
int flags;
struct thread *td;
{
SMBVDEBUG("flags=%04x\n", flags);
return 0;
}
/*
* Do operations associated with quotas, not supported
*/
/* ARGSUSED */
static int
smbfs_quotactl(mp, cmd, uid, arg, td)
struct mount *mp;
int cmd;
uid_t uid;
caddr_t arg;
struct thread *td;
{
SMBVDEBUG("return EOPNOTSUPP\n");
return EOPNOTSUPP;
}
/*ARGSUSED*/
int
smbfs_init(struct vfsconf *vfsp)
{
#ifndef SMP
int name[2];
int olen, ncpu, plen, error;
name[0] = CTL_HW;
name[1] = HW_NCPU;
error = kernel_sysctl(curthread, name, 2, &ncpu, &olen, NULL, 0, &plen);
if (error == 0 && ncpu > 1)
printf("warning: smbfs module compiled without SMP support.");
#endif
#ifdef SMBFS_USEZONE
smbfsmount_zone = zinit("SMBFSMOUNT", sizeof(struct smbmount), 0, 0, 1);
#endif
smbfs_pbuf_freecnt = nswbuf / 2 + 1;
SMBVDEBUG("done.\n");
return 0;
}
/*ARGSUSED*/
int
smbfs_uninit(struct vfsconf *vfsp)
{
SMBVDEBUG("done.\n");
return 0;
}
/*
* smbfs_statfs call
*/
int
smbfs_statfs(struct mount *mp, struct statfs *sbp, struct thread *td)
{
struct smbmount *smp = VFSTOSMBFS(mp);
struct smbnode *np = smp->sm_root;
struct smb_share *ssp = smp->sm_share;
struct smb_cred scred;
int error = 0;
if (np == NULL)
return EINVAL;
sbp->f_iosize = SSTOVC(ssp)->vc_txmax; /* optimal transfer block size */
sbp->f_spare2 = 0; /* placeholder */
smb_makescred(&scred, td, td->td_proc->p_ucred);
if (SMB_DIALECT(SSTOVC(ssp)) >= SMB_DIALECT_LANMAN2_0)
error = smbfs_smb_statfs2(ssp, sbp, &scred);
else
error = smbfs_smb_statfs(ssp, sbp, &scred);
if (error)
return error;
sbp->f_flags = 0; /* copy of mount exported flags */
if (sbp != &mp->mnt_stat) {
sbp->f_fsid = mp->mnt_stat.f_fsid; /* file system id */
sbp->f_owner = mp->mnt_stat.f_owner; /* user that mounted the filesystem */
sbp->f_type = mp->mnt_vfc->vfc_typenum; /* type of filesystem */
bcopy(mp->mnt_stat.f_mntonname, sbp->f_mntonname, MNAMELEN);
bcopy(mp->mnt_stat.f_mntfromname, sbp->f_mntfromname, MNAMELEN);
}
strncpy(sbp->f_fstypename, mp->mnt_vfc->vfc_name, MFSNAMELEN);
return 0;
}
/*
* Flush out the buffer cache
*/
/* ARGSUSED */
static int
smbfs_sync(mp, waitfor, cred, td)
struct mount *mp;
int waitfor;
struct ucred *cred;
struct thread *td;
{
struct vnode *vp;
int error, allerror = 0;
/*
* Force stale buffer cache information to be flushed.
*/
loop:
for (vp = TAILQ_FIRST(&mp->mnt_nvnodelist);
vp != NULL;
vp = TAILQ_NEXT(vp, v_nmntvnodes)) {
/*
* If the vnode that we are about to sync is no longer
* associated with this mount point, start over.
*/
if (vp->v_mount != mp)
goto loop;
#ifndef FB_RELENG3
if (VOP_ISLOCKED(vp, NULL) || TAILQ_EMPTY(&vp->v_dirtyblkhd) ||
#else
if (VOP_ISLOCKED(vp) || TAILQ_EMPTY(&vp->v_dirtyblkhd) ||
#endif
waitfor == MNT_LAZY)
continue;
if (vget(vp, LK_EXCLUSIVE, td))
goto loop;
error = VOP_FSYNC(vp, cred, waitfor, td);
if (error)
allerror = error;
vput(vp);
}
return (allerror);
}
#if __FreeBSD_version < 400009
/*
* smbfs flat namespace lookup. Unsupported.
*/
/* ARGSUSED */
static int smbfs_vget(mp, ino, vpp)
struct mount *mp;
ino_t ino;
struct vnode **vpp;
{
return (EOPNOTSUPP);
}
/* ARGSUSED */
static int smbfs_fhtovp(mp, fhp, nam, vpp, exflagsp, credanonp)
struct mount *mp;
struct fid *fhp;
struct sockaddr *nam;
struct vnode **vpp;
int *exflagsp;
struct ucred **credanonp;
{
return (EINVAL);
}
/*
* Vnode pointer to File handle, should never happen either
*/
/* ARGSUSED */
static int
smbfs_vptofh(vp, fhp)
struct vnode *vp;
struct fid *fhp;
{
return (EINVAL);
}
#endif /* __FreeBSD_version < 400009 */

1334
sys/fs/smbfs/smbfs_vnops.c Normal file

File diff suppressed because it is too large Load Diff