diff options
author | davide <davide@FreeBSD.org> | 2013-05-04 14:03:18 +0000 |
---|---|---|
committer | davide <davide@FreeBSD.org> | 2013-05-04 14:03:18 +0000 |
commit | 49171951e3c2ee391cc14135ca9389ecb4e38f47 (patch) | |
tree | 58f50a43b89521ebbbf95593be5439c98bbdde90 /sys/netsmb | |
parent | 6473a2540f9533d31ae4872e4485cd1f7eb2e402 (diff) | |
download | FreeBSD-src-49171951e3c2ee391cc14135ca9389ecb4e38f47.zip FreeBSD-src-49171951e3c2ee391cc14135ca9389ecb4e38f47.tar.gz |
Completely rewrite the interface to smbdev switching from dev_clone
to cdevpriv(9). This commit changes the semantic of mount_smbfs
in userland as well, which now passes file descriptor in order to
to mount a specific filesystem istance.
Reviewed by: attilio, ed
Tested by: martymac
Diffstat (limited to 'sys/netsmb')
-rw-r--r-- | sys/netsmb/smb_dev.c | 221 | ||||
-rw-r--r-- | sys/netsmb/smb_dev.h | 20 |
2 files changed, 107 insertions, 134 deletions
diff --git a/sys/netsmb/smb_dev.c b/sys/netsmb/smb_dev.c index 5315f3f7..681397a 100644 --- a/sys/netsmb/smb_dev.c +++ b/sys/netsmb/smb_dev.c @@ -29,6 +29,7 @@ __FBSDID("$FreeBSD$"); #include <sys/param.h> #include <sys/kernel.h> +#include <sys/capability.h> #include <sys/module.h> #include <sys/systm.h> #include <sys/conf.h> @@ -55,20 +56,16 @@ __FBSDID("$FreeBSD$"); #include <netsmb/smb_subr.h> #include <netsmb/smb_dev.h> -#define SMB_GETDEV(dev) ((struct smb_dev*)(dev)->si_drv1) -#define SMB_CHECKMINOR(dev) do { \ - sdp = SMB_GETDEV(dev); \ - if (sdp == NULL) return ENXIO; \ - } while(0) +static struct cdev *nsmb_dev; static d_open_t nsmb_dev_open; -static d_close_t nsmb_dev_close; static d_ioctl_t nsmb_dev_ioctl; MODULE_DEPEND(netsmb, libiconv, 1, 1, 2); MODULE_VERSION(netsmb, NSMB_VERSION); static int smb_version = NSMB_VERSION; +struct sx smb_lock; SYSCTL_DECL(_net_smb); @@ -76,110 +73,97 @@ SYSCTL_INT(_net_smb, OID_AUTO, version, CTLFLAG_RD, &smb_version, 0, ""); static MALLOC_DEFINE(M_NSMBDEV, "NETSMBDEV", "NET/SMB device"); - -/* -int smb_dev_queue(struct smb_dev *ndp, struct smb_rq *rqp, int prio); -*/ - static struct cdevsw nsmb_cdevsw = { .d_version = D_VERSION, - .d_flags = D_NEEDGIANT | D_NEEDMINOR, .d_open = nsmb_dev_open, - .d_close = nsmb_dev_close, .d_ioctl = nsmb_dev_ioctl, .d_name = NSMB_NAME }; -static eventhandler_tag nsmb_dev_tag; -static struct clonedevs *nsmb_clones; - -static void -nsmb_dev_clone(void *arg, struct ucred *cred, char *name, int namelen, - struct cdev **dev) +static int +nsmb_dev_init(void) { - int i, u; - if (*dev != NULL) - return; + nsmb_dev = make_dev(&nsmb_cdevsw, 0, UID_ROOT, GID_OPERATOR, + 0600, "nsmb"); + if (nsmb_dev == NULL) + return (ENOMEM); + return (0); +} - if (strcmp(name, NSMB_NAME) == 0) - u = -1; - else if (dev_stdclone(name, NULL, NSMB_NAME, &u) != 1) - return; - i = clone_create(&nsmb_clones, &nsmb_cdevsw, &u, dev, 0); - if (i) - *dev = make_dev_credf(MAKEDEV_REF, &nsmb_cdevsw, u, cred, - UID_ROOT, GID_WHEEL, 0600, "%s%d", NSMB_NAME, u); +static void +nsmb_dev_destroy(void) +{ + + MPASS(nsmb_dev != NULL); + destroy_dev(nsmb_dev); + nsmb_dev = NULL; } -static int -nsmb_dev_open(struct cdev *dev, int oflags, int devtype, struct thread *td) +static struct smb_dev * +smbdev_alloc(struct cdev *dev) { struct smb_dev *sdp; - struct ucred *cred = td->td_ucred; - int s; - - sdp = SMB_GETDEV(dev); - if (sdp && (sdp->sd_flags & NSMBFL_OPEN)) - return EBUSY; - if (sdp == NULL) { - sdp = malloc(sizeof(*sdp), M_NSMBDEV, M_WAITOK); - dev->si_drv1 = (void*)sdp; - } - /* - * XXX: this is just crazy - make a device for an already passed device... - * someone should take care of it. - */ - if ((dev->si_flags & SI_NAMED) == 0) - make_dev(&nsmb_cdevsw, dev2unit(dev), cred->cr_uid, - cred->cr_gid, 0700, NSMB_NAME"%d", dev2unit(dev)); - bzero(sdp, sizeof(*sdp)); -/* - STAILQ_INIT(&sdp->sd_rqlist); - STAILQ_INIT(&sdp->sd_rplist); - bzero(&sdp->sd_pollinfo, sizeof(struct selinfo)); -*/ - s = splimp(); + + sdp = malloc(sizeof(struct smb_dev), M_NSMBDEV, M_WAITOK | M_ZERO); + sdp->dev = dev; sdp->sd_level = -1; sdp->sd_flags |= NSMBFL_OPEN; - splx(s); - return 0; + sdp->refcount = 1; + return (sdp); +} + +void +sdp_dtor(void *arg) +{ + struct smb_dev *dev; + + dev = (struct smb_dev *)arg; + SMB_LOCK(); + sdp_trydestroy(dev); + SMB_UNLOCK(); } static int -nsmb_dev_close(struct cdev *dev, int flag, int fmt, struct thread *td) +nsmb_dev_open(struct cdev *dev, int oflags, int devtype, struct thread *td) { struct smb_dev *sdp; + int error; + + sdp = smbdev_alloc(dev); + error = devfs_set_cdevpriv(sdp, sdp_dtor); + if (error) { + free(sdp, M_NSMBDEV); + return (error); + } + return (0); +} + +void +sdp_trydestroy(struct smb_dev *sdp) +{ struct smb_vc *vcp; struct smb_share *ssp; struct smb_cred *scred; - int s; + SMB_LOCKASSERT(); + if (!sdp) + panic("No smb_dev upon device close"); + MPASS(sdp->refcount > 0); + sdp->refcount--; + if (sdp->refcount) + return; scred = malloc(sizeof(struct smb_cred), M_NSMBDEV, M_WAITOK); - SMB_CHECKMINOR(dev); - s = splimp(); - if ((sdp->sd_flags & NSMBFL_OPEN) == 0) { - splx(s); - free(scred, M_NSMBDEV); - return EBADF; - } - smb_makescred(scred, td, NULL); + smb_makescred(scred, curthread, NULL); ssp = sdp->sd_share; if (ssp != NULL) smb_share_rele(ssp, scred); vcp = sdp->sd_vc; if (vcp != NULL) smb_vc_rele(vcp, scred); -/* - smb_flushq(&sdp->sd_rqlist); - smb_flushq(&sdp->sd_rplist); -*/ - dev->si_drv1 = NULL; - free(sdp, M_NSMBDEV); - destroy_dev_sched(dev); - splx(s); free(scred, M_NSMBDEV); - return 0; + free(sdp, M_NSMBDEV); + return; } @@ -192,11 +176,11 @@ nsmb_dev_ioctl(struct cdev *dev, u_long cmd, caddr_t data, int flag, struct thre struct smb_cred *scred; int error = 0; - SMB_CHECKMINOR(dev); - if ((sdp->sd_flags & NSMBFL_OPEN) == 0) - return EBADF; - + error = devfs_get_cdevpriv((void **)&sdp); + if (error) + return (error); scred = malloc(sizeof(struct smb_cred), M_NSMBDEV, M_WAITOK); + SMB_LOCK(); smb_makescred(scred, td, NULL); switch (cmd) { case SMBIOC_OPENSESSION: @@ -345,6 +329,7 @@ nsmb_dev_ioctl(struct cdev *dev, u_long cmd, caddr_t data, int flag, struct thre } out: free(scred, M_NSMBDEV); + SMB_UNLOCK(); return error; } @@ -363,18 +348,18 @@ nsmb_dev_load(module_t mod, int cmd, void *arg) smb_sm_done(); break; } - clone_setup(&nsmb_clones); - nsmb_dev_tag = EVENTHANDLER_REGISTER(dev_clone, nsmb_dev_clone, 0, 1000); + error = nsmb_dev_init(); + if (error) + break; + sx_init(&smb_lock, "samba device lock"); break; case MOD_UNLOAD: smb_iod_done(); error = smb_sm_done(); if (error) break; - EVENTHANDLER_DEREGISTER(dev_clone, nsmb_dev_tag); - drain_dev_clone_events(); - clone_cleanup(&nsmb_clones); - destroy_dev_drain(&nsmb_cdevsw); + nsmb_dev_destroy(); + sx_destroy(&smb_lock); break; default: error = EINVAL; @@ -385,58 +370,40 @@ nsmb_dev_load(module_t mod, int cmd, void *arg) DEV_MODULE (dev_netsmb, nsmb_dev_load, 0); -/* - * Convert a file descriptor to appropriate smb_share pointer - */ -static struct file* -nsmb_getfp(struct filedesc* fdp, int fd, int flag) -{ - struct file* fp; - - FILEDESC_SLOCK(fdp); - if ((fp = fget_locked(fdp, fd)) == NULL || (fp->f_flag & flag) == 0) { - FILEDESC_SUNLOCK(fdp); - return (NULL); - } - fhold(fp); - FILEDESC_SUNLOCK(fdp); - return (fp); -} - int smb_dev2share(int fd, int mode, struct smb_cred *scred, - struct smb_share **sspp) + struct smb_share **sspp, struct smb_dev **ssdp) { - struct file *fp; - struct vnode *vp; + struct file *fp, *fptmp; struct smb_dev *sdp; struct smb_share *ssp; - struct cdev *dev; + struct thread *td; int error; - fp = nsmb_getfp(scred->scr_td->td_proc->p_fd, fd, FREAD | FWRITE); - if (fp == NULL) - return EBADF; - vp = fp->f_vnode; - if (vp == NULL) { - fdrop(fp, curthread); - return EBADF; - } - if (vp->v_type != VCHR) { - fdrop(fp, curthread); - return EBADF; - } - dev = vp->v_rdev; - SMB_CHECKMINOR(dev); + td = curthread; + error = fget(td, fd, CAP_READ, &fp); + if (error) + return (error); + fptmp = td->td_fpop; + td->td_fpop = fp; + error = devfs_get_cdevpriv((void **)&sdp); + td->td_fpop = fptmp; + fdrop(fp, td); + if (error || sdp == NULL) + return (error); + SMB_LOCK(); + *ssdp = sdp; ssp = sdp->sd_share; if (ssp == NULL) { - fdrop(fp, curthread); - return ENOTCONN; + SMB_UNLOCK(); + return (ENOTCONN); } error = smb_share_get(ssp, LK_EXCLUSIVE, scred); - if (error == 0) + if (error == 0) { + sdp->refcount++; *sspp = ssp; - fdrop(fp, curthread); + } + SMB_UNLOCK(); return error; } diff --git a/sys/netsmb/smb_dev.h b/sys/netsmb/smb_dev.h index 67149e1..25d08b9 100644 --- a/sys/netsmb/smb_dev.h +++ b/sys/netsmb/smb_dev.h @@ -155,22 +155,28 @@ struct smbioc_rw { STAILQ_HEAD(smbrqh, smb_rq); struct smb_dev { + struct cdev * dev; int sd_opened; int sd_level; struct smb_vc * sd_vc; /* reference to VC */ struct smb_share *sd_share; /* reference to share if any */ int sd_poll; int sd_seq; -/* struct ifqueue sd_rdqueue; - struct ifqueue sd_wrqueue; - struct selinfo sd_pollinfo; - struct smbrqh sd_rqlist; - struct smbrqh sd_rplist; - struct ucred *sd_owner;*/ int sd_flags; + int refcount; + int usecount; }; +extern struct sx smb_lock; +#define SMB_LOCK() sx_xlock(&smb_lock) +#define SMB_UNLOCK() sx_unlock(&smb_lock) +#define SMB_LOCKASSERT() sx_assert(&smb_lock, SA_XLOCKED) + struct smb_cred; + +void sdp_dtor(void *arg); +void sdp_trydestroy(struct smb_dev *dev); + /* * Compound user interface */ @@ -185,7 +191,7 @@ int smb_usr_simplerequest(struct smb_share *ssp, struct smbioc_rq *data, int smb_usr_t2request(struct smb_share *ssp, struct smbioc_t2rq *data, struct smb_cred *scred); int smb_dev2share(int fd, int mode, struct smb_cred *scred, - struct smb_share **sspp); + struct smb_share **sspp, struct smb_dev **ssdp); #endif /* _KERNEL */ |