version 1.16.2.3, 2007/02/26 09:10:58 |
version 1.16.2.4, 2007/09/03 14:40:30 |
|
|
* 2. Redistributions in binary form must reproduce the above copyright |
* 2. Redistributions in binary form must reproduce the above copyright |
* notice, this list of conditions and the following disclaimer in the |
* notice, this list of conditions and the following disclaimer in the |
* documentation and/or other materials provided with the distribution. |
* documentation and/or other materials provided with the distribution. |
* 3. The name of the company nor the name of the author may be used to |
|
* endorse or promote products derived from this software without specific |
|
* prior written permission. |
|
* |
* |
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS |
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS |
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED |
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED |
Line 44 __KERNEL_RCSID(0, "$NetBSD$"); |
|
Line 41 __KERNEL_RCSID(0, "$NetBSD$"); |
|
#include <sys/dirent.h> |
#include <sys/dirent.h> |
#include <sys/kauth.h> |
#include <sys/kauth.h> |
#include <sys/fstrans.h> |
#include <sys/fstrans.h> |
|
#include <sys/proc.h> |
|
|
#include <lib/libkern/libkern.h> |
#include <lib/libkern/libkern.h> |
|
|
#include <fs/puffs/puffs_msgif.h> |
#include <fs/puffs/puffs_msgif.h> |
#include <fs/puffs/puffs_sys.h> |
#include <fs/puffs/puffs_sys.h> |
|
|
|
#include <nfs/nfsproto.h> /* for fh sizes */ |
|
|
VFS_PROTOS(puffs); |
VFS_PROTOS(puffs); |
|
|
MALLOC_DEFINE(M_PUFFS, "puffs", "pass-to-userspace file system structures"); |
MALLOC_JUSTDEFINE(M_PUFFS, "puffs", "Pass-to-Userspace Framework File System"); |
|
|
#ifndef PUFFS_PNODEBUCKETS |
#ifndef PUFFS_PNODEBUCKETS |
#define PUFFS_PNODEBUCKETS 256 |
#define PUFFS_PNODEBUCKETS 256 |
#endif |
#endif |
#ifndef PUFFS_MAXPNODEBUCKETS |
#ifndef PUFFS_MAXPNODEBUCKETS |
#define PUFFS_MAXPNODEBUCKETS 65536 |
#define PUFFS_MAXPNODEBUCKETS 8192 |
#endif |
#endif |
int puffs_pnodebuckets = PUFFS_PNODEBUCKETS; |
int puffs_pnodebuckets_default = PUFFS_PNODEBUCKETS; |
|
int puffs_maxpnodebuckets = PUFFS_MAXPNODEBUCKETS; |
|
|
int |
int |
puffs_mount(struct mount *mp, const char *path, void *data, |
puffs_mount(struct mount *mp, const char *path, void *data, size_t *data_len, |
struct nameidata *ndp, struct lwp *l) |
struct lwp *l) |
{ |
{ |
struct puffs_mount *pmp = NULL; |
struct puffs_mount *pmp = NULL; |
struct puffs_args *args; |
struct puffs_kargs *args; |
char namebuf[PUFFSNAMESIZE+sizeof(PUFFS_NAMEPREFIX)+1]; /* spooky */ |
char fstype[_VFS_NAMELEN]; |
|
char *p; |
int error = 0, i; |
int error = 0, i; |
|
|
|
if (*data_len < sizeof *args) |
|
return EINVAL; |
|
|
if (mp->mnt_flag & MNT_GETARGS) { |
if (mp->mnt_flag & MNT_GETARGS) { |
pmp = MPTOPUFFSMP(mp); |
pmp = MPTOPUFFSMP(mp); |
return copyout(&pmp->pmp_args, data, sizeof(struct puffs_args)); |
*(struct puffs_kargs *)data = pmp->pmp_args; |
|
*data_len = sizeof *args; |
|
return 0; |
} |
} |
|
|
/* update is not supported currently */ |
/* update is not supported currently */ |
Line 86 puffs_mount(struct mount *mp, const char |
|
Line 93 puffs_mount(struct mount *mp, const char |
|
if (!data) |
if (!data) |
return EINVAL; |
return EINVAL; |
|
|
MALLOC(args, struct puffs_args *, sizeof(struct puffs_args), |
MALLOC(args, struct puffs_kargs *, sizeof(struct puffs_kargs), |
M_PUFFS, M_WAITOK); |
M_PUFFS, M_WAITOK); |
|
|
error = copyin(data, args, sizeof(struct puffs_args)); |
*args = *(struct puffs_kargs *)data; |
if (error) |
|
goto out; |
|
|
|
/* devel phase */ |
/* devel phase */ |
if (args->pa_vers != (PUFFSVERSION | PUFFSDEVELVERS)) { |
if (args->pa_vers != (PUFFSVERSION | PUFFSDEVELVERS)) { |
Line 100 puffs_mount(struct mount *mp, const char |
|
Line 105 puffs_mount(struct mount *mp, const char |
|
goto out; |
goto out; |
} |
} |
|
|
/* nuke spy bits */ |
if ((args->pa_flags & ~PUFFS_KFLAG_MASK) != 0) { |
args->pa_flags &= PUFFS_KFLAG_MASK; |
printf("puffs_mount: invalid KFLAGs 0x%x\n", args->pa_flags); |
|
error = EINVAL; |
|
goto out; |
|
} |
|
if ((args->pa_fhflags & ~PUFFS_FHFLAG_MASK) != 0) { |
|
printf("puffs_mount: invalid FHFLAGs 0x%x\n", args->pa_fhflags); |
|
error = EINVAL; |
|
goto out; |
|
} |
|
|
|
/* use dummy value for passthrough */ |
|
if (args->pa_fhflags & PUFFS_FHFLAG_PASSTHROUGH) |
|
args->pa_fhsize = sizeof(struct fid); |
|
|
|
/* sanitize file handle length */ |
|
if (PUFFS_TOFHSIZE(args->pa_fhsize) > FHANDLE_SIZE_MAX) { |
|
printf("puffs_mount: handle size %zu too large\n", |
|
args->pa_fhsize); |
|
error = EINVAL; |
|
goto out; |
|
} |
|
/* sanity check file handle max sizes */ |
|
if (args->pa_fhsize && args->pa_fhflags & PUFFS_FHFLAG_PROTOMASK) { |
|
size_t kfhsize = PUFFS_TOFHSIZE(args->pa_fhsize); |
|
|
|
if (args->pa_fhflags & PUFFS_FHFLAG_NFSV2) { |
|
if (NFSX_FHTOOBIG_P(kfhsize, 0)) { |
|
printf("puffs_mount: fhsize larger than " |
|
"NFSv2 max %d\n", |
|
PUFFS_FROMFHSIZE(NFSX_V2FH)); |
|
error = EINVAL; |
|
goto out; |
|
} |
|
} |
|
|
|
if (args->pa_fhflags & PUFFS_FHFLAG_NFSV3) { |
|
if (NFSX_FHTOOBIG_P(kfhsize, 1)) { |
|
printf("puffs_mount: fhsize larger than " |
|
"NFSv3 max %d\n", |
|
PUFFS_FROMFHSIZE(NFSX_V3FHMAX)); |
|
error = EINVAL; |
|
goto out; |
|
} |
|
} |
|
} |
|
|
|
/* don't allow non-printing characters (like my sweet umlauts.. snif) */ |
|
args->pa_typename[sizeof(args->pa_typename)-1] = '\0'; |
|
for (p = args->pa_typename; *p; p++) |
|
if (*p < ' ' || *p > '~') |
|
*p = '.'; |
|
|
|
args->pa_mntfromname[sizeof(args->pa_mntfromname)-1] = '\0'; |
|
for (p = args->pa_mntfromname; *p; p++) |
|
if (*p < ' ' || *p > '~') |
|
*p = '.'; |
|
|
/* build real name */ |
/* build real name */ |
(void)strlcpy(namebuf, PUFFS_NAMEPREFIX, sizeof(namebuf)); |
(void)strlcpy(fstype, PUFFS_TYPEPREFIX, sizeof(fstype)); |
(void)strlcat(namebuf, args->pa_name, sizeof(namebuf)); |
(void)strlcat(fstype, args->pa_typename, sizeof(fstype)); |
|
|
/* inform user server if it got the max request size it wanted */ |
/* inform user server if it got the max request size it wanted */ |
if (args->pa_maxreqlen == 0 || args->pa_maxreqlen > PUFFS_REQ_MAXSIZE) |
if (args->pa_maxreqlen == 0 || args->pa_maxreqlen > PUFFS_REQ_MAXSIZE) |
args->pa_maxreqlen = PUFFS_REQ_MAXSIZE; |
args->pa_maxreqlen = PUFFS_REQ_MAXSIZE; |
else if (args->pa_maxreqlen < PUFFS_REQSTRUCT_MAX) |
else if (args->pa_maxreqlen < 2*PUFFS_REQSTRUCT_MAX) |
args->pa_maxreqlen = PUFFS_REQSTRUCT_MAX; |
args->pa_maxreqlen = 2*PUFFS_REQSTRUCT_MAX; |
(void)strlcpy(args->pa_name, namebuf, sizeof(args->pa_name)); |
(void)strlcpy(args->pa_typename, fstype, sizeof(args->pa_typename)); |
|
|
error = copyout(args, data, sizeof(struct puffs_args)); |
if (args->pa_nhashbuckets == 0) |
if (error) |
args->pa_nhashbuckets = puffs_pnodebuckets_default; |
goto out; |
if (args->pa_nhashbuckets < 1) |
|
args->pa_nhashbuckets = 1; |
|
if (args->pa_nhashbuckets > PUFFS_MAXPNODEBUCKETS) { |
|
args->pa_nhashbuckets = puffs_maxpnodebuckets; |
|
printf("puffs_mount: using %d hash buckets. " |
|
"adjust puffs_maxpnodebuckets for more\n", |
|
puffs_maxpnodebuckets); |
|
} |
|
|
error = set_statvfs_info(path, UIO_USERSPACE, namebuf, |
error = set_statvfs_info(path, UIO_USERSPACE, args->pa_mntfromname, |
UIO_SYSSPACE, mp, l); |
UIO_SYSSPACE, fstype, mp, l); |
if (error) |
if (error) |
goto out; |
goto out; |
mp->mnt_stat.f_iosize = DEV_BSIZE; |
mp->mnt_stat.f_iosize = DEV_BSIZE; |
|
|
|
/* |
|
* We can't handle the VFS_STATVFS() mount_domount() does |
|
* after VFS_MOUNT() because we'd deadlock, so handle it |
|
* here already. |
|
*/ |
|
copy_statvfs_info(&args->pa_svfsb, mp); |
|
(void)memcpy(&mp->mnt_stat, &args->pa_svfsb, sizeof(mp->mnt_stat)); |
|
|
MALLOC(pmp, struct puffs_mount *, sizeof(struct puffs_mount), |
MALLOC(pmp, struct puffs_mount *, sizeof(struct puffs_mount), |
M_PUFFS, M_WAITOK | M_ZERO); |
M_PUFFS, M_WAITOK | M_ZERO); |
|
|
Line 139 puffs_mount(struct mount *mp, const char |
|
Line 214 puffs_mount(struct mount *mp, const char |
|
pmp->pmp_req_maxsize = args->pa_maxreqlen; |
pmp->pmp_req_maxsize = args->pa_maxreqlen; |
pmp->pmp_args = *args; |
pmp->pmp_args = *args; |
|
|
/* puffs_node hash buckets */ |
pmp->pmp_npnodehash = args->pa_nhashbuckets; |
pmp->pmp_npnodehash = puffs_pnodebuckets; |
|
if (pmp->pmp_npnodehash < 1) |
|
pmp->pmp_npnodehash = 1; |
|
if (pmp->pmp_npnodehash > PUFFS_MAXPNODEBUCKETS) |
|
pmp->pmp_npnodehash = PUFFS_MAXPNODEBUCKETS; |
|
pmp->pmp_pnodehash = malloc |
pmp->pmp_pnodehash = malloc |
(sizeof(struct puffs_pnode_hashlist *) * pmp->pmp_npnodehash, |
(sizeof(struct puffs_pnode_hashlist *) * pmp->pmp_npnodehash, |
M_PUFFS, M_WAITOK); |
M_PUFFS, M_WAITOK); |
Line 161 puffs_mount(struct mount *mp, const char |
|
Line 231 puffs_mount(struct mount *mp, const char |
|
goto out; |
goto out; |
} |
} |
|
|
simple_lock_init(&pmp->pmp_lock); |
/* XXX: check parameters */ |
|
pmp->pmp_root_cookie = args->pa_root_cookie; |
|
pmp->pmp_root_vtype = args->pa_root_vtype; |
|
pmp->pmp_root_vsize = args->pa_root_vsize; |
|
pmp->pmp_root_rdev = args->pa_root_rdev; |
|
|
|
mutex_init(&pmp->pmp_lock, MUTEX_DEFAULT, IPL_NONE); |
|
cv_init(&pmp->pmp_req_waiter_cv, "puffsget"); |
|
cv_init(&pmp->pmp_refcount_cv, "puffsref"); |
|
cv_init(&pmp->pmp_unmounting_cv, "puffsum"); |
TAILQ_INIT(&pmp->pmp_req_touser); |
TAILQ_INIT(&pmp->pmp_req_touser); |
TAILQ_INIT(&pmp->pmp_req_replywait); |
TAILQ_INIT(&pmp->pmp_req_replywait); |
TAILQ_INIT(&pmp->pmp_req_sizepark); |
TAILQ_INIT(&pmp->pmp_req_sizepark); |
Line 180 puffs_mount(struct mount *mp, const char |
|
Line 259 puffs_mount(struct mount *mp, const char |
|
return error; |
return error; |
} |
} |
|
|
/* |
|
* This is called from the first "Hello, I'm alive" ioctl |
|
* from userspace. |
|
*/ |
|
int |
int |
puffs_start2(struct puffs_mount *pmp, struct puffs_startreq *sreq) |
puffs_start(struct mount *mp, int flags, struct lwp *l) |
{ |
{ |
struct puffs_node *pn; |
struct puffs_mount *pmp = MPTOPUFFSMP(mp); |
struct mount *mp; |
|
|
|
mp = PMPTOMP(pmp); |
|
|
|
simple_lock(&pmp->pmp_lock); |
KASSERT(pmp->pmp_status == PUFFSTAT_MOUNTING); |
|
|
/* |
|
* if someone has issued a VFS_ROOT() already, fill in the |
|
* vnode cookie. |
|
*/ |
|
pn = NULL; |
|
if (pmp->pmp_root) { |
|
pn = VPTOPP(pmp->pmp_root); |
|
pn->pn_cookie = sreq->psr_cookie; |
|
} |
|
|
|
/* We're good to fly */ |
|
pmp->pmp_rootcookie = sreq->psr_cookie; |
|
pmp->pmp_status = PUFFSTAT_RUNNING; |
pmp->pmp_status = PUFFSTAT_RUNNING; |
simple_unlock(&pmp->pmp_lock); |
|
|
|
/* do the VFS_STATVFS() we missed out on in sys_mount() */ |
|
copy_statvfs_info(&sreq->psr_sb, mp); |
|
(void)memcpy(&mp->mnt_stat, &sreq->psr_sb, sizeof(mp->mnt_stat)); |
|
mp->mnt_stat.f_iosize = DEV_BSIZE; |
|
|
|
DPRINTF(("puffs_start2: root vp %p, cur root pnode %p, cookie %p\n", |
|
pmp->pmp_root, pn, sreq->psr_cookie)); |
|
|
|
return 0; |
return 0; |
} |
} |
|
|
int |
int |
puffs_start(struct mount *mp, int flags, struct lwp *l) |
|
{ |
|
|
|
/* |
|
* This cannot travel to userspace, as this is called from |
|
* the kernel context of the process doing mount(2). But |
|
* it's probably a safe bet that the process doing mount(2) |
|
* realizes it needs to start the filesystem also... |
|
*/ |
|
return 0; |
|
} |
|
|
|
int |
|
puffs_unmount(struct mount *mp, int mntflags, struct lwp *l) |
puffs_unmount(struct mount *mp, int mntflags, struct lwp *l) |
{ |
{ |
struct puffs_mount *pmp; |
struct puffs_mount *pmp; |
Line 264 puffs_unmount(struct mount *mp, int mntf |
|
Line 301 puffs_unmount(struct mount *mp, int mntf |
|
* If we are not DYING, we should ask userspace's opinion |
* If we are not DYING, we should ask userspace's opinion |
* about the situation |
* about the situation |
*/ |
*/ |
simple_lock(&pmp->pmp_lock); |
mutex_enter(&pmp->pmp_lock); |
if (pmp->pmp_status != PUFFSTAT_DYING) { |
if (pmp->pmp_status != PUFFSTAT_DYING) { |
pmp->pmp_unmounting = 1; |
pmp->pmp_unmounting = 1; |
simple_unlock(&pmp->pmp_lock); |
mutex_exit(&pmp->pmp_lock); |
|
|
unmount_arg.pvfsr_flags = mntflags; |
unmount_arg.pvfsr_flags = mntflags; |
unmount_arg.pvfsr_pid = puffs_lwp2pid(l); |
puffs_cidcvt(&unmount_arg.pvfsr_cid, l); |
|
|
error = puffs_vfstouser(pmp, PUFFS_VFS_UNMOUNT, |
error = puffs_vfstouser(pmp, PUFFS_VFS_UNMOUNT, |
&unmount_arg, sizeof(unmount_arg)); |
&unmount_arg, sizeof(unmount_arg)); |
DPRINTF(("puffs_unmount: error %d force %d\n", error, force)); |
DPRINTF(("puffs_unmount: error %d force %d\n", error, force)); |
|
|
simple_lock(&pmp->pmp_lock); |
mutex_enter(&pmp->pmp_lock); |
pmp->pmp_unmounting = 0; |
pmp->pmp_unmounting = 0; |
wakeup(&pmp->pmp_unmounting); |
cv_broadcast(&pmp->pmp_unmounting_cv); |
} |
} |
|
|
/* |
/* |
Line 291 puffs_unmount(struct mount *mp, int mntf |
|
Line 328 puffs_unmount(struct mount *mp, int mntf |
|
puffs_nukebypmp(pmp); |
puffs_nukebypmp(pmp); |
|
|
/* |
/* |
* Sink waiters. This is still not perfect, since the |
* Wait until there are no more users for the mount resource. |
* draining is done after userret, not when they really |
* Notice that this is hooked against transport_close |
* exit the file system. It will probably work as almost |
* and return from touser. In an ideal world, it would |
* no call will block and therefore cause a context switch |
* be hooked against final return from all operations. |
* and therefore will protected by the biglock after |
* But currently it works well enough, since nobody |
* exiting userspace. But ... it's an imperfect world. |
* does weird blocking voodoo after return from touser(). |
*/ |
*/ |
while (pmp->pmp_req_touser_waiters != 0) |
while (pmp->pmp_refcount != 0) |
ltsleep(&pmp->pmp_req_touser_waiters, PVFS, |
cv_wait(&pmp->pmp_refcount_cv, &pmp->pmp_lock); |
"puffsink", 0, &pmp->pmp_lock); |
mutex_exit(&pmp->pmp_lock); |
simple_unlock(&pmp->pmp_lock); |
|
|
|
/* free resources now that we hopefully have no waiters left */ |
/* free resources now that we hopefully have no waiters left */ |
|
cv_destroy(&pmp->pmp_unmounting_cv); |
|
cv_destroy(&pmp->pmp_refcount_cv); |
|
cv_destroy(&pmp->pmp_req_waiter_cv); |
|
mutex_destroy(&pmp->pmp_lock); |
|
|
free(pmp->pmp_pnodehash, M_PUFFS); |
free(pmp->pmp_pnodehash, M_PUFFS); |
FREE(pmp, M_PUFFS); |
FREE(pmp, M_PUFFS); |
error = 0; |
error = 0; |
} else { |
} else { |
simple_unlock(&pmp->pmp_lock); |
mutex_exit(&pmp->pmp_lock); |
} |
} |
|
|
out: |
out: |
Line 322 puffs_unmount(struct mount *mp, int mntf |
|
Line 363 puffs_unmount(struct mount *mp, int mntf |
|
int |
int |
puffs_root(struct mount *mp, struct vnode **vpp) |
puffs_root(struct mount *mp, struct vnode **vpp) |
{ |
{ |
struct puffs_mount *pmp; |
struct puffs_mount *pmp = MPTOPUFFSMP(mp); |
struct puffs_node *pn; |
|
struct vnode *vp; |
|
|
|
pmp = MPTOPUFFSMP(mp); |
return puffs_pnode2vnode(pmp, pmp->pmp_root_cookie, 1, vpp); |
|
|
/* |
|
* pmp_lock must be held if vref()'ing or vrele()'ing the |
|
* root vnode. the latter is controlled by puffs_inactive(). |
|
*/ |
|
simple_lock(&pmp->pmp_lock); |
|
vp = pmp->pmp_root; |
|
if (vp) { |
|
simple_lock(&vp->v_interlock); |
|
simple_unlock(&pmp->pmp_lock); |
|
pn = VPTOPP(vp); |
|
if (vget(vp, LK_EXCLUSIVE | LK_RETRY | LK_INTERLOCK)) |
|
goto grabnew; |
|
*vpp = vp; |
|
return 0; |
|
} else |
|
simple_unlock(&pmp->pmp_lock); |
|
|
|
/* XXX: this is wrong, so FIXME */ |
|
grabnew: |
|
|
|
/* |
|
* So, didn't have the magic root vnode available. |
|
* No matter, grab another an stuff it with the cookie. |
|
*/ |
|
if (puffs_getvnode(mp, pmp->pmp_rootcookie, VDIR, 0, 0, &vp)) |
|
panic("sloppy programming"); |
|
|
|
simple_lock(&pmp->pmp_lock); |
|
/* |
|
* check if by mysterious force someone else created a root |
|
* vnode while we were executing. |
|
*/ |
|
if (pmp->pmp_root) { |
|
vref(pmp->pmp_root); |
|
simple_unlock(&pmp->pmp_lock); |
|
puffs_putvnode(vp); |
|
vn_lock(pmp->pmp_root, LK_EXCLUSIVE | LK_RETRY); |
|
*vpp = pmp->pmp_root; |
|
return 0; |
|
} |
|
|
|
/* store cache */ |
|
vp->v_flag = VROOT; |
|
pmp->pmp_root = vp; |
|
simple_unlock(&pmp->pmp_lock); |
|
|
|
vn_lock(pmp->pmp_root, LK_EXCLUSIVE | LK_RETRY); |
|
|
|
*vpp = vp; |
|
return 0; |
|
} |
|
|
|
int |
|
puffs_quotactl(struct mount *mp, int cmd, uid_t uid, void *arg, struct lwp *l) |
|
{ |
|
|
|
return EOPNOTSUPP; |
|
} |
} |
|
|
int |
int |
Line 408 puffs_statvfs(struct mount *mp, struct s |
|
Line 389 puffs_statvfs(struct mount *mp, struct s |
|
/* too big for stack */ |
/* too big for stack */ |
MALLOC(statvfs_arg, struct puffs_vfsreq_statvfs *, |
MALLOC(statvfs_arg, struct puffs_vfsreq_statvfs *, |
sizeof(struct puffs_vfsreq_statvfs), M_PUFFS, M_WAITOK | M_ZERO); |
sizeof(struct puffs_vfsreq_statvfs), M_PUFFS, M_WAITOK | M_ZERO); |
statvfs_arg->pvfsr_pid = puffs_lwp2pid(l); |
puffs_cidcvt(&statvfs_arg->pvfsr_cid, l); |
|
|
error = puffs_vfstouser(pmp, PUFFS_VFS_STATVFS, |
error = puffs_vfstouser(pmp, PUFFS_VFS_STATVFS, |
statvfs_arg, sizeof(*statvfs_arg)); |
statvfs_arg, sizeof(*statvfs_arg)); |
Line 433 puffs_statvfs(struct mount *mp, struct s |
|
Line 414 puffs_statvfs(struct mount *mp, struct s |
|
} |
} |
|
|
static int |
static int |
pageflush(struct mount *mp, int waitfor, int suspending) |
pageflush(struct mount *mp, kauth_cred_t cred, |
|
int waitfor, int suspending, struct lwp *l) |
{ |
{ |
struct puffs_node *pn; |
struct puffs_node *pn; |
struct vnode *vp, *nvp; |
struct vnode *vp, *nvp; |
int error, rv, ppflags; |
int error, rv; |
|
|
KASSERT(((waitfor == MNT_WAIT) && suspending) == 0); |
KASSERT(((waitfor == MNT_WAIT) && suspending) == 0); |
KASSERT((suspending == 0) |
KASSERT((suspending == 0) |
Line 445 pageflush(struct mount *mp, int waitfor, |
|
Line 427 pageflush(struct mount *mp, int waitfor, |
|
&& fstrans_getstate(mp) == FSTRANS_SUSPENDING)); |
&& fstrans_getstate(mp) == FSTRANS_SUSPENDING)); |
|
|
error = 0; |
error = 0; |
ppflags = PGO_CLEANIT | PGO_ALLPAGES; |
|
if (waitfor == MNT_WAIT) |
|
ppflags |= PGO_SYNCIO; |
|
|
|
/* |
/* |
* Sync all cached data from regular vnodes (which are not |
* Sync all cached data from regular vnodes (which are not |
Line 520 pageflush(struct mount *mp, int waitfor, |
|
Line 499 pageflush(struct mount *mp, int waitfor, |
|
* storage. |
* storage. |
* TODO: Maybe also hint the user server of this twist? |
* TODO: Maybe also hint the user server of this twist? |
*/ |
*/ |
simple_lock(&vp->v_interlock); |
if (suspending || waitfor == MNT_LAZY) { |
if (suspending || waitfor == MNT_LAZY) |
simple_lock(&vp->v_interlock); |
pn->pn_stat |= PNODE_SUSPEND; |
pn->pn_stat |= PNODE_SUSPEND; |
rv = VOP_PUTPAGES(vp, 0, 0, ppflags); |
simple_unlock(&vp->v_interlock); |
|
} |
|
rv = VOP_FSYNC(vp, cred, waitfor, 0, 0, l); |
if (suspending || waitfor == MNT_LAZY) { |
if (suspending || waitfor == MNT_LAZY) { |
simple_lock(&vp->v_interlock); |
simple_lock(&vp->v_interlock); |
pn->pn_stat &= ~PNODE_SUSPEND; |
pn->pn_stat &= ~PNODE_SUSPEND; |
Line 547 puffs_sync(struct mount *mp, int waitfor |
|
Line 528 puffs_sync(struct mount *mp, int waitfor |
|
|
|
PUFFS_VFSREQ(sync); |
PUFFS_VFSREQ(sync); |
|
|
error = pageflush(mp, waitfor, 0); |
error = pageflush(mp, cred, waitfor, 0, l); |
|
|
/* sync fs */ |
/* sync fs */ |
sync_arg.pvfsr_waitfor = waitfor; |
sync_arg.pvfsr_waitfor = waitfor; |
puffs_credcvt(&sync_arg.pvfsr_cred, cred); |
puffs_credcvt(&sync_arg.pvfsr_cred, cred); |
sync_arg.pvfsr_pid = puffs_lwp2pid(l); |
puffs_cidcvt(&sync_arg.pvfsr_cid, l); |
|
|
rv = puffs_vfstouser(MPTOPUFFSMP(mp), PUFFS_VFS_SYNC, |
rv = puffs_vfstouser(MPTOPUFFSMP(mp), PUFFS_VFS_SYNC, |
&sync_arg, sizeof(sync_arg)); |
&sync_arg, sizeof(sync_arg)); |
Line 563 puffs_sync(struct mount *mp, int waitfor |
|
Line 544 puffs_sync(struct mount *mp, int waitfor |
|
} |
} |
|
|
int |
int |
puffs_vget(struct mount *mp, ino_t ino, struct vnode **vpp) |
puffs_fhtovp(struct mount *mp, struct fid *fhp, struct vnode **vpp) |
{ |
{ |
|
struct puffs_mount *pmp = MPTOPUFFSMP(mp); |
|
struct puffs_vfsreq_fhtonode *fhtonode_argp; |
|
struct vnode *vp; |
|
void *fhdata; |
|
size_t argsize, fhlen; |
|
int error; |
|
|
return EOPNOTSUPP; |
if (pmp->pmp_args.pa_fhsize == 0) |
} |
return EOPNOTSUPP; |
|
|
#if 0 |
if (pmp->pmp_args.pa_fhflags & PUFFS_FHFLAG_PASSTHROUGH) { |
/*ARGSUSED*/ |
fhlen = fhp->fid_len; |
int |
fhdata = fhp; |
puffs_fhtovp(struct mount *mp, struct fid *fhp, struct vnode **vpp) |
} else { |
{ |
fhlen = PUFFS_FROMFHSIZE(fhp->fid_len); |
|
fhdata = fhp->fid_data; |
|
|
return EOPNOTSUPP; |
if (pmp->pmp_args.pa_fhflags & PUFFS_FHFLAG_DYNAMIC) { |
|
if (pmp->pmp_args.pa_fhsize < fhlen) |
|
return EINVAL; |
|
} else { |
|
if (pmp->pmp_args.pa_fhsize != fhlen) |
|
return EINVAL; |
|
} |
|
} |
|
|
|
argsize = sizeof(struct puffs_vfsreq_fhtonode) + fhlen; |
|
fhtonode_argp = malloc(argsize, M_PUFFS, M_ZERO | M_WAITOK); |
|
fhtonode_argp->pvfsr_dsize = fhlen; |
|
memcpy(fhtonode_argp->pvfsr_data, fhdata, fhlen); |
|
|
|
error = puffs_vfstouser(pmp, PUFFS_VFS_FHTOVP, fhtonode_argp, argsize); |
|
if (error) |
|
goto out; |
|
|
|
error = puffs_pnode2vnode(pmp, fhtonode_argp->pvfsr_fhcookie, 1, &vp); |
|
DPRINTF(("puffs_fhtovp: got cookie %p, existing vnode %p\n", |
|
fhtonode_argp->pvfsr_fhcookie, vp)); |
|
if (error) { |
|
error = puffs_getvnode(mp, fhtonode_argp->pvfsr_fhcookie, |
|
fhtonode_argp->pvfsr_vtype, fhtonode_argp->pvfsr_size, |
|
fhtonode_argp->pvfsr_rdev, &vp); |
|
if (error) |
|
goto out; |
|
vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); |
|
} |
|
|
|
*vpp = vp; |
|
out: |
|
free(fhtonode_argp, M_PUFFS); |
|
return error; |
} |
} |
|
|
/*ARGSUSED*/ |
|
int |
int |
puffs_vptofh(struct vnode *vp, struct fid *fhp) |
puffs_vptofh(struct vnode *vp, struct fid *fhp, size_t *fh_size) |
{ |
{ |
|
struct puffs_mount *pmp = MPTOPUFFSMP(vp->v_mount); |
|
struct puffs_vfsreq_nodetofh *nodetofh_argp; |
|
size_t argsize, fhlen; |
|
int error; |
|
|
return EOPNOTSUPP; |
if (pmp->pmp_args.pa_fhsize == 0) |
|
return EOPNOTSUPP; |
|
|
|
/* if file handles are static len, we can test len immediately */ |
|
if (((pmp->pmp_args.pa_fhflags & PUFFS_FHFLAG_DYNAMIC) == 0) |
|
&& ((pmp->pmp_args.pa_fhflags & PUFFS_FHFLAG_PASSTHROUGH) == 0) |
|
&& (PUFFS_FROMFHSIZE(*fh_size) < pmp->pmp_args.pa_fhsize)) { |
|
*fh_size = PUFFS_TOFHSIZE(pmp->pmp_args.pa_fhsize); |
|
return E2BIG; |
|
} |
|
|
|
if (pmp->pmp_args.pa_fhflags & PUFFS_FHFLAG_PASSTHROUGH) |
|
fhlen = *fh_size; |
|
else |
|
fhlen = PUFFS_FROMFHSIZE(*fh_size); |
|
|
|
argsize = sizeof(struct puffs_vfsreq_nodetofh) + fhlen; |
|
nodetofh_argp = malloc(argsize, M_PUFFS, M_ZERO | M_WAITOK); |
|
nodetofh_argp->pvfsr_fhcookie = VPTOPNC(vp); |
|
nodetofh_argp->pvfsr_dsize = fhlen; |
|
|
|
error = puffs_vfstouser(pmp, PUFFS_VFS_VPTOFH, nodetofh_argp, argsize); |
|
|
|
if (pmp->pmp_args.pa_fhflags & PUFFS_FHFLAG_PASSTHROUGH) |
|
fhlen = nodetofh_argp->pvfsr_dsize; |
|
else if (pmp->pmp_args.pa_fhflags & PUFFS_FHFLAG_DYNAMIC) |
|
fhlen = PUFFS_TOFHSIZE(nodetofh_argp->pvfsr_dsize); |
|
else |
|
fhlen = PUFFS_TOFHSIZE(pmp->pmp_args.pa_fhsize); |
|
|
|
if (error) { |
|
if (error == E2BIG) |
|
*fh_size = fhlen; |
|
goto out; |
|
} |
|
|
|
if (fhlen > FHANDLE_SIZE_MAX) { |
|
/* XXX: wrong direction */ |
|
error = EINVAL; |
|
goto out; |
|
} |
|
|
|
if (*fh_size < fhlen) { |
|
*fh_size = fhlen; |
|
error = E2BIG; |
|
goto out; |
|
} |
|
*fh_size = fhlen; |
|
|
|
if (fhp) { |
|
if (pmp->pmp_args.pa_fhflags & PUFFS_FHFLAG_PASSTHROUGH) { |
|
memcpy(fhp, nodetofh_argp->pvfsr_data, fhlen); |
|
} else { |
|
fhp->fid_len = *fh_size; |
|
memcpy(fhp->fid_data, nodetofh_argp->pvfsr_data, |
|
nodetofh_argp->pvfsr_dsize); |
|
} |
|
} |
|
|
|
out: |
|
free(nodetofh_argp, M_PUFFS); |
|
return error; |
} |
} |
#endif |
|
|
|
void |
void |
puffs_init() |
puffs_init() |
{ |
{ |
|
|
#ifdef _LKM |
|
malloc_type_attach(M_PUFFS); |
malloc_type_attach(M_PUFFS); |
pool_init(&puffs_pnpool, sizeof(struct puffs_node), 0, 0, 0, |
|
"puffspnpl", &pool_allocator_nointr); |
|
#endif |
|
|
|
return; |
pool_init(&puffs_pnpool, sizeof(struct puffs_node), 0, 0, 0, |
|
"puffpnpl", &pool_allocator_nointr, IPL_NONE); |
|
puffs_transport_init(); |
|
puffs_msgif_init(); |
} |
} |
|
|
void |
void |
puffs_done() |
puffs_done() |
{ |
{ |
|
|
#ifdef _LKM |
puffs_msgif_destroy(); |
|
puffs_transport_destroy(); |
pool_destroy(&puffs_pnpool); |
pool_destroy(&puffs_pnpool); |
malloc_type_detach(M_PUFFS); |
|
#endif |
|
|
|
return; |
malloc_type_detach(M_PUFFS); |
} |
} |
|
|
int |
int |
Line 633 puffs_suspendctl(struct mount *mp, int c |
|
Line 715 puffs_suspendctl(struct mount *mp, int c |
|
break; |
break; |
puffs_suspendtouser(pmp, PUFFS_SUSPEND_START); |
puffs_suspendtouser(pmp, PUFFS_SUSPEND_START); |
|
|
error = pageflush(mp, 0, 1); |
error = pageflush(mp, FSCRED, 0, 1, curlwp); |
if (error == 0) |
if (error == 0) |
error = fstrans_setstate(mp, FSTRANS_SUSPENDED); |
error = fstrans_setstate(mp, FSTRANS_SUSPENDED); |
|
|
Line 673 const struct vnodeopv_desc * const puffs |
|
Line 755 const struct vnodeopv_desc * const puffs |
|
|
|
struct vfsops puffs_vfsops = { |
struct vfsops puffs_vfsops = { |
MOUNT_PUFFS, |
MOUNT_PUFFS, |
|
sizeof (struct puffs_kargs), |
puffs_mount, /* mount */ |
puffs_mount, /* mount */ |
puffs_start, /* start */ |
puffs_start, /* start */ |
puffs_unmount, /* unmount */ |
puffs_unmount, /* unmount */ |
puffs_root, /* root */ |
puffs_root, /* root */ |
puffs_quotactl, /* quotactl */ |
(void *)eopnotsupp, /* quotactl */ |
puffs_statvfs, /* statvfs */ |
puffs_statvfs, /* statvfs */ |
puffs_sync, /* sync */ |
puffs_sync, /* sync */ |
puffs_vget, /* vget */ |
(void *)eopnotsupp, /* vget */ |
(void *)eopnotsupp, /* fhtovp */ |
puffs_fhtovp, /* fhtovp */ |
(void *)eopnotsupp, /* vptofh */ |
puffs_vptofh, /* vptofh */ |
puffs_init, /* init */ |
puffs_init, /* init */ |
NULL, /* reinit */ |
NULL, /* reinit */ |
puffs_done, /* done */ |
puffs_done, /* done */ |