3269 lines
87 KiB
C
3269 lines
87 KiB
C
#ident "@(#)rfs_serve.c 1.1 92/07/30 SMI"
|
|
|
|
/* Copyright (c) 1984 AT&T */
|
|
/* All Rights Reserved */
|
|
|
|
/* THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF AT&T */
|
|
/* The copyright notice above does not evidence any */
|
|
/* actual or intended publication of such source code. */
|
|
|
|
/* #ident "@(#)kern-port:nudnix/serve.c 10.43" */
|
|
/*
|
|
* RFS server.
|
|
*/
|
|
|
|
#include <sys/types.h>
|
|
#include <sys/param.h>
|
|
#include <sys/signal.h>
|
|
#include <sys/file.h>
|
|
#include <sys/kmem_alloc.h>
|
|
#include <rpc/rpc.h>
|
|
#include <sys/stream.h>
|
|
#include <sys/user.h>
|
|
#include <sys/vnode.h>
|
|
#include <sys/sysmacros.h>
|
|
#include <sys/systm.h>
|
|
#include <sys/errno.h>
|
|
#include <sys/vfs.h>
|
|
#include <nfs/nfs.h>
|
|
#include <sys/mount.h>
|
|
#include <sys/proc.h>
|
|
#include <sys/stat.h>
|
|
#include <sys/debug.h>
|
|
#include <sys/conf.h>
|
|
#include <sys/uio.h>
|
|
#include <sys/dirent.h>
|
|
#include <sys/ioctl.h>
|
|
#include <sys/pathname.h>
|
|
#include <sys/fcntl.h>
|
|
#include <rfs/rfs_misc.h>
|
|
#include <rfs/sema.h>
|
|
#include <rfs/comm.h>
|
|
#include <rfs/nserve.h>
|
|
#include <rfs/cirmgr.h>
|
|
#include <rfs/message.h>
|
|
#include <rfs/rdebug.h>
|
|
#include <rfs/recover.h>
|
|
#include <rfs/rfs_serve.h>
|
|
#include <rfs/rfs_mnt.h>
|
|
#include <rfs/rfs_xdr.h>
|
|
#include <rfs/adv.h>
|
|
#include <rfs/hetero.h>
|
|
#include <rfs/idtab.h>
|
|
#include <vm/hat.h>
|
|
#include <vm/as.h>
|
|
#include <vm/seg.h>
|
|
#include <vm/seg_vn.h>
|
|
|
|
int rs_read();
|
|
int rs_write();
|
|
int rs_open();
|
|
int rs_close();
|
|
int rs_creat();
|
|
int rs_link();
|
|
int rs_unlink();
|
|
int rs_exec();
|
|
int rs_chdir();
|
|
int rs_mknod();
|
|
int rs_chmod();
|
|
int rs_chown();
|
|
int rs_stat();
|
|
int rs_seek();
|
|
int rs_fstat();
|
|
int rs_utime();
|
|
int rs_access();
|
|
int rs_statfs();
|
|
int rs_fstatfs();
|
|
int rs_ioctl();
|
|
int rs_utssys();
|
|
int rs_chroot();
|
|
int rs_fcntl();
|
|
int rs_rmdir();
|
|
int rs_mkdir();
|
|
int rs_getdents();
|
|
int rs_srmount();
|
|
int rs_srumount();
|
|
int rs_link1();
|
|
int rs_coredump();
|
|
int rs_iput();
|
|
int rs_iupdate();
|
|
int rs_uupdate();
|
|
int rs_clientop();
|
|
int rs_rsignal();
|
|
int rs_badop();
|
|
|
|
/*
|
|
* RFS server ops table.
|
|
* Note: these must match the numbering of RFS syscalls in message.h.
|
|
*/
|
|
int (*serv_op[])() = {
|
|
rs_badop, rs_badop, rs_badop,
|
|
rs_read, /* DUREAD 3 */
|
|
rs_write, /* DUWRITE 4 */
|
|
rs_open, /* DUOPEN 5 */
|
|
rs_close, /* DUCLOSE 6 */
|
|
rs_badop,
|
|
rs_creat, /* DUCREAT 8 */
|
|
rs_link, /* DULINK 9 */
|
|
rs_unlink, /* DUUNLINK 10 */
|
|
rs_exec, /* DUEXEC 11 */
|
|
rs_chdir, /* DUCHDIR 12 */
|
|
rs_badop,
|
|
rs_mknod, /* DUMKNOD 14 */
|
|
rs_chmod, /* DUCHMOD 15 */
|
|
rs_chown, /* DUCHOWN 16 */
|
|
rs_badop,
|
|
rs_stat, /* DUSTAT 18 */
|
|
rs_seek, /* DUSEEK 19 */
|
|
rs_badop,
|
|
rs_clientop, /* DUMOUNT 21 */
|
|
rs_clientop, /* DUUMOUNT 22 */
|
|
rs_badop, rs_badop, rs_badop, rs_badop, rs_badop,
|
|
rs_fstat, /* DUFSTAT 28 */
|
|
rs_badop,
|
|
rs_utime, /* DUUTIME 30 */
|
|
rs_badop, rs_badop,
|
|
rs_access, /* DUACCESS 33 */
|
|
rs_badop,
|
|
rs_statfs, /* DUSTATFS 35 */
|
|
rs_badop, rs_badop,
|
|
rs_fstatfs, /* DUFSTATFS 38 */
|
|
rs_badop, rs_badop, rs_badop, rs_badop, rs_badop, rs_badop, rs_badop,
|
|
rs_badop, rs_badop, rs_badop, rs_badop, rs_badop,
|
|
rs_clientop, /* DUSYSACCT 51 */
|
|
rs_badop, rs_badop,
|
|
rs_ioctl, /* DUIOCTL 54 */
|
|
rs_badop, rs_badop,
|
|
rs_utssys, /* DUUTSSYS 57 */
|
|
rs_badop,
|
|
rs_exec, /* DUEXECE 59 */
|
|
rs_badop,
|
|
rs_chroot, /* DUCHROOT 61 */
|
|
rs_fcntl, /* DUFCNTL 62 */
|
|
rs_badop, rs_badop, rs_badop, rs_badop, rs_badop, rs_badop, rs_badop,
|
|
rs_clientop, /* DUADVERTISE 70 */
|
|
rs_clientop, /* DUUNADVERTISE 71 */
|
|
rs_clientop, /* DURMOUNT 72 */
|
|
rs_clientop, /* DURUMOUNT 73 */
|
|
rs_badop, rs_badop, rs_badop, rs_badop, rs_badop,
|
|
rs_rmdir, /* DURMDIR 79 */
|
|
rs_mkdir, /* DUMKDIR 80 */
|
|
rs_getdents, /* DUGETDENTS 81 */
|
|
rs_badop, rs_badop, rs_badop, rs_badop, rs_badop, rs_badop, rs_badop,
|
|
rs_badop, rs_badop, rs_badop, rs_badop, rs_badop, rs_badop, rs_badop,
|
|
rs_badop,
|
|
rs_srmount, /* DUSRMOUNT 97 */
|
|
rs_srumount, /* DUSRUMOUNT 98 */
|
|
rs_badop, rs_badop, rs_badop, rs_badop, rs_badop, rs_badop, rs_badop,
|
|
rs_badop, /* DUCOPYIN 106 */
|
|
rs_badop, /* DUCOPYOUT 107 */
|
|
rs_badop,
|
|
rs_link1, /* DULINK1 109 */
|
|
rs_badop,
|
|
rs_coredump, /* DUCOREDUMP 111 */
|
|
rs_write, /* DUWRITEI 112 */
|
|
rs_read, /* DUREADI 113 */
|
|
rs_badop,
|
|
rs_badop, /* DULBMOUNT 115 */
|
|
rs_badop, rs_badop, rs_badop,
|
|
rs_rsignal, /* DURSIGNAL 119 */
|
|
rs_badop, rs_badop, rs_badop, rs_badop, rs_badop,
|
|
rs_badop, rs_badop, rs_badop, rs_badop, rs_badop,
|
|
rs_badop,
|
|
rs_iput, /* DUIPUT 131 */
|
|
rs_iupdate, /* DUIUPDATE 132 */
|
|
rs_uupdate, /* DUIUPDATE 133 */
|
|
rs_badop,
|
|
};
|
|
|
|
|
|
extern rcvd_t cr_rcvd();
|
|
extern sndd_t cr_sndd();
|
|
extern struct serv_proc *sp_alloc();
|
|
extern struct rd_user *cr_rduser();
|
|
extern rcvd_t rd_recover;
|
|
void chkrsig();
|
|
extern mblk_t *alocbuf();
|
|
extern mblk_t *salocbuf();
|
|
extern void setrsig();
|
|
extern void make_response();
|
|
extern char *strcpy();
|
|
extern struct vnode *rfs_cdir;
|
|
|
|
/* For physio() on raw devices */
|
|
#define SEGSTART ((addr_t) MAXBSIZE)
|
|
#define SEGSIZE (MAXBSIZE * 16)
|
|
u_int segsize = SEGSIZE;
|
|
struct as *rs_getas();
|
|
|
|
serve(sp)
|
|
struct serv_proc *sp;
|
|
{
|
|
extern rcvd_t serve_dq();
|
|
rcvd_t gift; /* what the requestor wanted */
|
|
register struct request *msg_in;
|
|
register struct sndd *sdp; /* reply path back to requestor */
|
|
int insize, outsize; /* size of out/incoming msg */
|
|
int i; /* temporary variable */
|
|
mblk_t *bp, *out_bp;
|
|
struct message *mp;
|
|
int error;
|
|
struct proc *p;
|
|
extern struct ucred *crcopy();
|
|
|
|
/* If got unexpected signal, try to exit gracefully */
|
|
if (setjmp(&u.u_qsave)) {
|
|
DUPRINT1(DB_SERVE, "server: unexpected signal, exiting\n");
|
|
return;
|
|
}
|
|
|
|
ASSERT(sp->s_proc == u.u_procp);
|
|
p = sp->s_proc;
|
|
|
|
/* ignore all signals, except SIGKILL, SIGTERM, SIGUSR1 */
|
|
for (i=0; i<NSIG; i++) {
|
|
u.u_signal[i] = SIG_IGN;
|
|
u.u_sigmask[i] =
|
|
~(sigmask(SIGKILL)|sigmask(SIGTERM)|sigmask(SIGUSR1));
|
|
}
|
|
u.u_signal[SIGKILL] = SIG_DFL;
|
|
u.u_signal[SIGTERM] = SIG_DFL;
|
|
u.u_signal[SIGUSR1] = SIG_DFL;
|
|
p->p_sig = 0;
|
|
p->p_cursig = 0;
|
|
p->p_sigmask = ~(sigmask(SIGKILL)|sigmask(SIGTERM)|sigmask(SIGUSR1));
|
|
p->p_sigignore = ~(sigmask(SIGKILL)|sigmask(SIGTERM)|sigmask(SIGUSR1));
|
|
p->p_sigcatch = 0;
|
|
|
|
/* Don't share credentials with parent */
|
|
u.u_cred = crcopy(u.u_cred);
|
|
u.u_groups[0] = NOGROUP; /* Don't inherit group list from parent */
|
|
|
|
/* Create an sd to send back response. */
|
|
if ((sp->s_sdp = cr_sndd()) == (sndd_t) NULL) {
|
|
if (s_active.sl_head)
|
|
psignal(s_active.sl_head->s_proc, SIGUSR1);
|
|
return;
|
|
}
|
|
sdp = sp->s_sdp;
|
|
|
|
while (TRUE) {
|
|
bcopy ("rfs:server", u.u_comm, (u_int)11);
|
|
sdp->sd_queue = NULL;
|
|
sdp->sd_stat = (SDUSED | SDSERVE);
|
|
sdp->sd_srvproc = (struct proc *) NULL;
|
|
sp->s_epid = 0;
|
|
sp->s_sysid = 0;
|
|
u.u_cdir = rfs_cdir;
|
|
u.u_rdir = (struct vnode *) NULL;
|
|
|
|
/* Get request (bp) and rd to work on, quit if none */
|
|
if ((sp->s_rdp = serve_dq(&bp, &insize, sp)) == (rcvd_t) NULL)
|
|
return;
|
|
|
|
/* set up server process for syscall */
|
|
bcopy ("rfs:SERVER", u.u_comm, (u_int)11);
|
|
mp = (struct message *) bp->b_rptr;
|
|
msg_in = (struct request *) PTOMSG(bp->b_rptr);
|
|
gift = (rcvd_t) NULL;
|
|
error = 0;
|
|
sdp->sd_copycnt = 0;
|
|
sp->s_gdpp = GDP((queue_t *)mp->m_queue);
|
|
sp->s_sysid = sp->s_gdpp->sysid; /* Use SERVER's circuit id */
|
|
sp->s_epid = msg_in->rq_pid;
|
|
sp->s_op = msg_in->rq_opcode;
|
|
sp->s_mntindx = msg_in->rq_mntindx;
|
|
sp->s_fmode = RFSTOFFLAG(msg_in->rq_fmode);
|
|
u.u_uid = gluid(sp->s_gdpp, (ushort) msg_in->rq_uid);
|
|
u.u_gid = glgid(sp->s_gdpp, (ushort) msg_in->rq_gid);
|
|
u.u_error = 0;
|
|
u.u_rlimit[RLIMIT_FSIZE].rlim_cur =
|
|
msg_in->rq_ulimit << SCTRSHFT;
|
|
out_bp = (mblk_t *) NULL;
|
|
|
|
/* fail req. if resource is in funny state - e.g., fumount */
|
|
if (sp->s_op != DUSRMOUNT) {
|
|
if (srmount[sp->s_mntindx].sr_flags & MINTER) {
|
|
freemsg (bp);
|
|
DUPRINT1(DB_RECOVER, "req. MINTER resource\n");
|
|
continue;
|
|
}
|
|
/* following two sd fields used by recovery/fumount */
|
|
sdp->sd_mntindx = sp->s_mntindx;
|
|
sdp->sd_srvproc = sp->s_proc;
|
|
}
|
|
/* Service the request */
|
|
error = (*(serv_op[sp->s_op]))(sp, bp, &out_bp, &outsize, &gift);
|
|
|
|
/* Send response, if there is one */
|
|
if (out_bp) {
|
|
error = sndmsg(sdp, out_bp, outsize, gift);
|
|
if (error) {
|
|
/*
|
|
* Error: assume link down, decr. server count
|
|
* on this resource and wakeup recovery if last
|
|
*/
|
|
DUPRINT1 (DB_SERVE, "server sndmsg failed\n");
|
|
if (--srmount[sp->s_mntindx].sr_slpcnt == 0)
|
|
wakeup ((caddr_t) &srmount[sp->s_mntindx]);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Server ops -- one for each RFS remote system call.
|
|
*/
|
|
rs_open(sp, in_bp, out_bp, outsize, gift)
|
|
struct serv_proc *sp;
|
|
mblk_t *in_bp, **out_bp;
|
|
int *outsize;
|
|
rcvd_t *gift;
|
|
{
|
|
register struct request *msg_in;
|
|
struct response *msg_out;
|
|
register char *name;
|
|
struct vnode *vp = (struct vnode *) NULL;
|
|
int error = 0;
|
|
struct vattr va;
|
|
int mode, crtmode;
|
|
|
|
msg_in = (struct request *) PTOMSG(in_bp->b_rptr);
|
|
DUPRINT6(DB_SERVE,
|
|
"rs_open: sp %x, name %s, mode %x, crtmode %x, rd->vp %x\n",
|
|
sp, msg_in->rq_data, msg_in->rq_fmode, msg_in->rq_crtmode,
|
|
sp->s_rdp->rd_vnode);
|
|
|
|
/* Set client remote signal, if any */
|
|
setrsig(sp, in_bp);
|
|
|
|
/* Get file name and access mode from request message */
|
|
name = msg_in->rq_data;
|
|
mode = RFSTOOMODE(msg_in->rq_mode);
|
|
crtmode = (msg_in->rq_crtmode & 07777) & ~msg_in->rq_cmask;
|
|
|
|
/* Set the current working and root directories */
|
|
set_dir(sp->s_rdp, msg_in->rq_rrdir);
|
|
|
|
/* Recover if system call is interrupted */
|
|
if (setjmp(&u.u_qsave)) {
|
|
error = EINTR;
|
|
goto out;
|
|
}
|
|
/* Do the open */
|
|
if (error = rs_vnopen(name, UIOSEG_KERNEL, mode, crtmode, sp, &vp))
|
|
goto out;
|
|
|
|
/* Get attributes of new vnode to return to client */
|
|
if (error = VOP_GETATTR(vp, &va, u.u_cred))
|
|
goto out;
|
|
|
|
/* Make a receive descriptor for client requests on new vnode */
|
|
if (error = make_gift(vp, FILE_QSIZE, sp, gift))
|
|
goto out;
|
|
|
|
srmount[sp->s_mntindx].sr_refcnt++; /* New ref on this mnt point */
|
|
out:
|
|
chkrsig(sp, &error);
|
|
|
|
/* Make response message */
|
|
make_response(sp, &in_bp, error, vp, &va, out_bp, outsize);
|
|
|
|
msg_out = (struct response *) PTOMSG((*out_bp)->b_rptr);
|
|
msg_out->rp_cache = 0;
|
|
if (MND_LCK(va.va_mode))
|
|
msg_out->rp_cache |= RP_MNDLCK;
|
|
|
|
/* Free the request buffer (and the vnode if error) */
|
|
if (in_bp)
|
|
freemsg(in_bp);
|
|
if (error) {
|
|
if (vp)
|
|
VN_RELE(vp);
|
|
}
|
|
DUPRINT4(DB_SERVE, "rs_open: result %d, name %s, vp %x\n",
|
|
error, name, vp);
|
|
return (error);
|
|
}
|
|
|
|
/*ARGSUSED*/
|
|
rs_close(sp, in_bp, out_bp, outsize, gift)
|
|
struct serv_proc *sp;
|
|
mblk_t *in_bp, **out_bp;
|
|
int *outsize;
|
|
rcvd_t *gift;
|
|
{
|
|
register struct request *msg_in;
|
|
rcvd_t rdp;
|
|
struct vnode *vp = (struct vnode *) NULL;
|
|
int holdvp = 0;
|
|
int error = 0;
|
|
|
|
msg_in = (struct request *) PTOMSG(in_bp->b_rptr);
|
|
DUPRINT6(DB_SERVE, "rs_close: sp %x, mode %x, count %x, foffset %d, rd->vp %x\n", sp, msg_in->rq_mode, msg_in->rq_count, msg_in->rq_foffset, sp->s_rdp->rd_vnode);
|
|
|
|
/* Set client remote signal, if any */
|
|
setrsig(sp, in_bp);
|
|
|
|
/* Recover if system call is interrupted */
|
|
if (setjmp(&u.u_qsave)) {
|
|
error = EINTR;
|
|
goto out;
|
|
}
|
|
/* Get the vnode for the file to be closed */
|
|
rdp = sp->s_rdp;
|
|
vp = rdp->rd_vnode;
|
|
|
|
/* Release any locks held by this client on this file */
|
|
rsl_lockrelease(sp->s_rdp, sp->s_epid, (long) sp->s_mntindx);
|
|
|
|
if (vp->v_count == 1 && rdp->rd_user_list != NULL &&
|
|
rdp->rd_user_list->ru_fcount > 1) {
|
|
VN_HOLD(vp);
|
|
holdvp = 1;
|
|
}
|
|
error = VOP_CLOSE(vp, RFSTOFFLAG(msg_in->rq_mode),
|
|
msg_in->rq_count, u.u_cred);
|
|
|
|
if (holdvp)
|
|
VN_RELE(vp);
|
|
out:
|
|
chkrsig(sp, &error);
|
|
|
|
/* Adjust client user counts for recovery */
|
|
if (msg_in->rq_count == 1)
|
|
del_rduser(sp->s_rdp, sp);
|
|
|
|
/* Make response message */
|
|
make_response(sp, &in_bp, error, (struct vnode *) NULL,
|
|
(struct vattr *) NULL, out_bp, outsize);
|
|
|
|
/* Free the request buffer */
|
|
if (in_bp)
|
|
freemsg(in_bp);
|
|
|
|
DUPRINT3(DB_SERVE, "rs_close: result %d, vp %x\n", error, vp);
|
|
return (error);
|
|
}
|
|
|
|
rs_creat(sp, in_bp, out_bp, outsize, gift)
|
|
struct serv_proc *sp;
|
|
mblk_t *in_bp, **out_bp;
|
|
int *outsize;
|
|
rcvd_t *gift;
|
|
{
|
|
register struct request *msg_in;
|
|
struct response *msg_out;
|
|
register char *name;
|
|
struct vnode *vp = (struct vnode *) NULL;
|
|
int error = 0;
|
|
struct vattr va;
|
|
int mode, crtmode;
|
|
|
|
msg_in = (struct request *) PTOMSG(in_bp->b_rptr);
|
|
DUPRINT5(DB_SERVE, "rs_creat: sp %x, name %s, mode %x, rd->vp %x\n",
|
|
sp, msg_in->rq_data, msg_in->rq_fmode, sp->s_rdp->rd_vnode);
|
|
|
|
/* Set client remote signal, if any */
|
|
setrsig(sp, in_bp);
|
|
|
|
/* Get file name and create mode from request message */
|
|
name = msg_in->rq_data;
|
|
crtmode = (msg_in->rq_fmode & 07777) & ~msg_in->rq_cmask;
|
|
mode = FWRITE | FCREAT | FTRUNC;
|
|
|
|
/* Set the current working and root directories */
|
|
set_dir(sp->s_rdp, msg_in->rq_rrdir);
|
|
|
|
/* Recover if system call is interrupted */
|
|
if (setjmp(&u.u_qsave)) {
|
|
error = EINTR;
|
|
goto out;
|
|
}
|
|
/* Do the open */
|
|
if (error = rs_vnopen(name, UIOSEG_KERNEL, mode, crtmode, sp, &vp))
|
|
goto out;
|
|
|
|
/* Get attributes of new vnode to return to client */
|
|
if (error = VOP_GETATTR(vp, &va, u.u_cred))
|
|
goto out;
|
|
|
|
/* Make a receive descriptor for client requests on new vnode */
|
|
if (error = make_gift(vp, FILE_QSIZE, sp, gift))
|
|
goto out;
|
|
|
|
srmount[sp->s_mntindx].sr_refcnt++; /* New ref on this mnt point */
|
|
out:
|
|
chkrsig(sp, &error);
|
|
/* Make response message */
|
|
make_response(sp, &in_bp, error, vp, &va, out_bp, outsize);
|
|
|
|
msg_out = (struct response *) PTOMSG((*out_bp)->b_rptr);
|
|
msg_out->rp_cache = 0;
|
|
if (MND_LCK(va.va_mode))
|
|
msg_out->rp_cache |= RP_MNDLCK;
|
|
|
|
/* Free the request buffer (and the vnode if error) */
|
|
if (in_bp)
|
|
freemsg(in_bp);
|
|
if (error) {
|
|
if (vp)
|
|
VN_RELE(vp);
|
|
}
|
|
DUPRINT4(DB_SERVE, "rs_creat: result %d, name %s, vp %x\n",
|
|
error, name, vp);
|
|
return (error);
|
|
}
|
|
|
|
/*
|
|
* First half of remote link system call: just does a lookup on first name
|
|
* No permission checking is done so that this can be used as a lookup op
|
|
* by an RFS client without any special permissions.
|
|
*/
|
|
rs_link(sp, in_bp, out_bp, outsize, gift)
|
|
struct serv_proc *sp;
|
|
mblk_t *in_bp, **out_bp;
|
|
int *outsize;
|
|
rcvd_t *gift;
|
|
{
|
|
register struct request *msg_in;
|
|
register char *name;
|
|
struct vnode *vp = (struct vnode *) NULL;
|
|
int error = 0;
|
|
struct vattr va;
|
|
|
|
msg_in = (struct request *) PTOMSG(in_bp->b_rptr);
|
|
DUPRINT4(DB_SERVE, "rs_link: sp %x, name %s, rd->vp %x\n",
|
|
sp, msg_in->rq_data, sp->s_rdp->rd_vnode);
|
|
|
|
/* Get file name and access mode from request message */
|
|
name = msg_in->rq_data;
|
|
|
|
/* Set the current working and root directories */
|
|
set_dir(sp->s_rdp, msg_in->rq_rrdir);
|
|
|
|
/* Get vnode for file to be linked */
|
|
if (error = rs_lookupname(name, UIOSEG_KERNEL, NO_FOLLOW, sp,
|
|
(struct vnode **) NULL, &vp))
|
|
goto out;
|
|
|
|
/* Get attributes of new vnode to return to client */
|
|
if (error = VOP_GETATTR(vp, &va, u.u_cred))
|
|
goto out;
|
|
|
|
/* Make a receive descriptor for client requests on new vnode */
|
|
if (error = make_gift(vp, FILE_QSIZE, sp, gift))
|
|
goto out;
|
|
srmount[sp->s_mntindx].sr_refcnt++; /* New ref on this mnt point */
|
|
out:
|
|
/* Make response message */
|
|
make_response(sp, &in_bp, error, vp, &va, out_bp, outsize);
|
|
|
|
/* Free the request buffer (and the vnode if error) */
|
|
if (in_bp)
|
|
freemsg(in_bp);
|
|
if (error) {
|
|
if (vp)
|
|
VN_RELE(vp);
|
|
}
|
|
DUPRINT4(DB_SERVE, "rs_link: result %d, name %s, vp %x\n",
|
|
error, name, vp);
|
|
return (error);
|
|
}
|
|
|
|
/*
|
|
* Second half of remote link system call: do the link.
|
|
*/
|
|
/*ARGSUSED*/
|
|
rs_link1(sp, in_bp, out_bp, outsize, gift)
|
|
struct serv_proc *sp;
|
|
mblk_t *in_bp, **out_bp;
|
|
int *outsize;
|
|
rcvd_t *gift;
|
|
{
|
|
register struct request *msg_in;
|
|
register char *name;
|
|
struct vnode *fvp = (struct vnode *) NULL;
|
|
struct vnode *tdvp = (struct vnode *) NULL;
|
|
int error = 0;
|
|
|
|
msg_in = (struct request *) PTOMSG(in_bp->b_rptr);
|
|
DUPRINT5(DB_SERVE,
|
|
"rs_link1: sp %x, name %s, fvp %x, rd->vp %x\n", sp,
|
|
msg_in->rq_data,
|
|
msg_in->rq_link ?
|
|
rcvd[msg_in->rq_link].rd_vnode : (struct vnode *) NULL,
|
|
sp->s_rdp->rd_vnode);
|
|
|
|
/* Get dest file name from request message */
|
|
name = msg_in->rq_data;
|
|
/* Get source vp: if rq_link == 0, source vp is not "on" this server */
|
|
if (msg_in->rq_link)
|
|
fvp = rcvd[msg_in->rq_link].rd_vnode;
|
|
else
|
|
fvp = (struct vnode *) NULL;
|
|
|
|
/* Set the current working and root directories */
|
|
set_dir(sp->s_rdp, msg_in->rq_rrdir);
|
|
|
|
/* Get vnode for file to be linked */
|
|
if (error = rs_lookupname(name, UIOSEG_KERNEL, NO_FOLLOW, sp,
|
|
&tdvp, (struct vnode **) NULL))
|
|
goto out;
|
|
|
|
/*
|
|
* Make sure both source vnode and target directory vnode are in
|
|
* the same vfs and that it is writeable.
|
|
*/
|
|
if (fvp == (struct vnode *) NULL || fvp->v_vfsp != tdvp->v_vfsp) {
|
|
error = EXDEV;
|
|
goto out;
|
|
}
|
|
if (tdvp->v_vfsp->vfs_flag & VFS_RDONLY) {
|
|
error = EROFS;
|
|
goto out;
|
|
}
|
|
/* Only super-user can link to directories */
|
|
if (fvp->v_type == VDIR && u.u_uid != 0) {
|
|
error = EPERM;
|
|
goto out;
|
|
}
|
|
|
|
/* do the link */
|
|
error = VOP_LINK(fvp, tdvp, name, u.u_cred);
|
|
out:
|
|
/* Make response message */
|
|
make_response(sp, &in_bp, error, (struct vnode *) NULL,
|
|
(struct vattr *) NULL, out_bp, outsize);
|
|
|
|
/* Free the request buffer and the directory vnode */
|
|
if (in_bp)
|
|
freemsg(in_bp);
|
|
if (tdvp)
|
|
VN_RELE(tdvp);
|
|
DUPRINT3(DB_SERVE, "rs_link1: result %d, name %s\n",
|
|
error, name);
|
|
return (error);
|
|
}
|
|
|
|
/*ARGSUSED*/
|
|
rs_unlink(sp, in_bp, out_bp, outsize, gift)
|
|
struct serv_proc *sp;
|
|
mblk_t *in_bp, **out_bp;
|
|
int *outsize;
|
|
rcvd_t *gift;
|
|
{
|
|
register struct request *msg_in;
|
|
register char *name;
|
|
struct vnode *vp = (struct vnode *) NULL;
|
|
struct vnode *dvp = (struct vnode *) NULL;
|
|
int error = 0;
|
|
|
|
msg_in = (struct request *) PTOMSG(in_bp->b_rptr);
|
|
DUPRINT4(DB_SERVE, "rs_unlink: sp %x, name %s, rd->vp %x\n",
|
|
sp, msg_in->rq_data, sp->s_rdp->rd_vnode);
|
|
|
|
/* Get dir name from request message */
|
|
name = msg_in->rq_data;
|
|
|
|
/* Set the current working and root directories */
|
|
set_dir(sp->s_rdp, msg_in->rq_rrdir);
|
|
|
|
/* Get vnode for file to be unlinked */
|
|
if (error = rs_lookupname(name, UIOSEG_KERNEL, NO_FOLLOW, sp,
|
|
&dvp, &vp))
|
|
goto out;
|
|
|
|
/* make sure there is an entry */
|
|
if (vp == (struct vnode *)0) {
|
|
error = ENOENT;
|
|
goto out;
|
|
}
|
|
/* make sure filesystem is writeable */
|
|
if (vp->v_vfsp->vfs_flag & VFS_RDONLY) {
|
|
error = EROFS;
|
|
goto out;
|
|
}
|
|
/* don't unlink the root of a mounted filesystem. */
|
|
if (vp->v_flag & VROOT) {
|
|
error = EBUSY;
|
|
goto out;
|
|
}
|
|
/* Only super-user can unlink directories */
|
|
if (vp->v_type == VDIR && u.u_uid != 0) {
|
|
error = EPERM;
|
|
goto out;
|
|
}
|
|
/* release vnode before removing */
|
|
VN_RELE(vp);
|
|
vp = (struct vnode *)0;
|
|
|
|
/* remove the file */
|
|
error = VOP_REMOVE(dvp, name, u.u_cred);
|
|
|
|
out:
|
|
/* Make response message */
|
|
make_response(sp, &in_bp, error, (struct vnode *) NULL,
|
|
(struct vattr *) NULL, out_bp, outsize);
|
|
|
|
/* Free the request buffer (and the vnode if error) */
|
|
if (in_bp)
|
|
freemsg(in_bp);
|
|
if (vp)
|
|
VN_RELE(vp);
|
|
if (dvp)
|
|
VN_RELE(dvp);
|
|
|
|
DUPRINT3(DB_SERVE, "rs_unlink: result %d, name %s\n", error, name);
|
|
return (error);
|
|
}
|
|
|
|
rs_chroot(sp, in_bp, out_bp, outsize, gift)
|
|
struct serv_proc *sp;
|
|
mblk_t *in_bp, **out_bp;
|
|
int *outsize;
|
|
rcvd_t *gift;
|
|
{
|
|
register struct request *msg_in;
|
|
register char *name;
|
|
struct vnode *vp = (struct vnode *) NULL;
|
|
int error = 0;
|
|
struct vattr va;
|
|
|
|
msg_in = (struct request *) PTOMSG(in_bp->b_rptr);
|
|
DUPRINT4(DB_SERVE, "rs_chroot: sp %x, name %s, rd->vp %x\n",
|
|
sp, msg_in->rq_data, sp->s_rdp->rd_vnode);
|
|
|
|
/* Get file name and access mode from request message */
|
|
name = msg_in->rq_data;
|
|
|
|
/* Set the current working and root directories */
|
|
set_dir(sp->s_rdp, msg_in->rq_rrdir);
|
|
|
|
/* Get vnode for directory to be chdir'ed to */
|
|
if (error = rs_lookupname(name, UIOSEG_KERNEL, NO_FOLLOW, sp,
|
|
(struct vnode **) NULL, &vp))
|
|
goto out;
|
|
|
|
/* Must be a directory */
|
|
if (vp->v_type != VDIR) {
|
|
error = ENOTDIR;
|
|
goto out;
|
|
}
|
|
/* Must have x access */
|
|
if (error = VOP_ACCESS(vp, VEXEC, u.u_cred))
|
|
goto out;
|
|
|
|
/* Get attributes of new vnode to return to client */
|
|
if (error = VOP_GETATTR(vp, &va, u.u_cred))
|
|
goto out;
|
|
|
|
/* Make a receive descriptor for client requests on new vnode */
|
|
if (error = make_gift(vp, FILE_QSIZE, sp, gift))
|
|
goto out;
|
|
|
|
srmount[sp->s_mntindx].sr_refcnt++; /* New ref on this mnt point */
|
|
out:
|
|
/* Make response message */
|
|
make_response(sp, &in_bp, error, vp, &va, out_bp, outsize);
|
|
|
|
/* Free the request buffer (and the vnode if error) */
|
|
if (in_bp)
|
|
freemsg(in_bp);
|
|
if (error) {
|
|
if (vp)
|
|
VN_RELE(vp);
|
|
}
|
|
DUPRINT4(DB_SERVE, "rs_chroot: result %d, name %s, vp %x\n",
|
|
error, name, vp);
|
|
return (error);
|
|
}
|
|
|
|
rs_exec(sp, in_bp, out_bp, outsize, gift)
|
|
struct serv_proc *sp;
|
|
mblk_t *in_bp, **out_bp;
|
|
int *outsize;
|
|
rcvd_t *gift;
|
|
{
|
|
register struct request *msg_in;
|
|
register struct response *msg_out;
|
|
register char *name;
|
|
struct vnode *vp = (struct vnode *) NULL;
|
|
int error = 0;
|
|
struct vattr va;
|
|
|
|
msg_in = (struct request *) PTOMSG(in_bp->b_rptr);
|
|
DUPRINT4(DB_SERVE, "rs_exec: sp %x, name %s, rd->vp %x\n",
|
|
sp, msg_in->rq_data, sp->s_rdp->rd_vnode);
|
|
|
|
/* Get file name and access mode from request message */
|
|
name = msg_in->rq_data;
|
|
|
|
/* Set the current working and root directories */
|
|
set_dir(sp->s_rdp, msg_in->rq_rrdir);
|
|
|
|
/* Get vnode for directory to be chroot'ed to */
|
|
if (error = rs_lookupname(name, UIOSEG_KERNEL, NO_FOLLOW, sp,
|
|
(struct vnode **) NULL, &vp))
|
|
goto out;
|
|
|
|
/* Must have x access */
|
|
if (error = VOP_ACCESS(vp, VEXEC, u.u_cred))
|
|
goto out;
|
|
|
|
/* Get attributes of new vnode to return to client */
|
|
if (error = VOP_GETATTR(vp, &va, u.u_cred))
|
|
goto out;
|
|
|
|
/* Make a receive descriptor for client requests on new vnode */
|
|
if (error = make_gift(vp, FILE_QSIZE, sp, gift))
|
|
goto out;
|
|
|
|
(*gift)->rd_qtype |= RDTEXT;
|
|
|
|
srmount[sp->s_mntindx].sr_refcnt++; /* New ref on this mnt point */
|
|
out:
|
|
/* Make response message */
|
|
make_response(sp, &in_bp, error, vp, &va, out_bp, outsize);
|
|
|
|
msg_out = (struct response *) PTOMSG((*out_bp)->b_rptr);
|
|
*outsize = sizeof (struct response) - DATASIZE + RFS_DIRSIZ;
|
|
msg_out->rp_mode = va.va_mode;
|
|
msg_out->rp_subyte = 0; /* Message contains data */
|
|
bcopy(name, (caddr_t) msg_out->rp_data, RFS_DIRSIZ);
|
|
|
|
/* Free the request buffer (and the vnode if error) */
|
|
if (in_bp)
|
|
freemsg(in_bp);
|
|
if (error) {
|
|
if (vp)
|
|
VN_RELE(vp);
|
|
}
|
|
DUPRINT4(DB_SERVE, "rs_exec: result %d, name %s, vp %x\n",
|
|
error, name, vp);
|
|
return (error);
|
|
}
|
|
|
|
/*ARGSUSED*/
|
|
rs_mknod(sp, in_bp, out_bp, outsize, gift)
|
|
struct serv_proc *sp;
|
|
mblk_t *in_bp, **out_bp;
|
|
int *outsize;
|
|
rcvd_t *gift;
|
|
{
|
|
register struct request *msg_in;
|
|
register char *name;
|
|
struct vnode *dvp = (struct vnode *) NULL;
|
|
struct vnode *vp = (struct vnode *) NULL;
|
|
struct vattr va;
|
|
int error = 0;
|
|
|
|
msg_in = (struct request *) PTOMSG(in_bp->b_rptr);
|
|
DUPRINT6(DB_SERVE, "rs_mknod: sp %x, name %s, mode %x, dev %x, rd-vp %x\n", sp, msg_in->rq_data, msg_in->rq_fmode, msg_in->rq_dev, sp->s_rdp->rd_vnode);
|
|
|
|
/* Get file name, type, mode and dev # from request message */
|
|
name = msg_in->rq_data;
|
|
vattr_null(&va);
|
|
va.va_mode = (msg_in->rq_fmode & 07777) & ~msg_in->rq_cmask;
|
|
va.va_type = RFSTOVT(msg_in->rq_fmode);
|
|
va.va_rdev = msg_in->rq_dev;
|
|
|
|
/* Set the current working and root directories */
|
|
set_dir(sp->s_rdp, msg_in->rq_rrdir);
|
|
|
|
/* Get vnode for directory of file to be mknod'ed */
|
|
if (error = rs_lookupname(name, UIOSEG_KERNEL, NO_FOLLOW, sp,
|
|
&dvp, (struct vnode **) NULL))
|
|
goto out;
|
|
|
|
/* Can't change mode on read-only filesystems */
|
|
if (dvp->v_vfsp->vfs_flag & VFS_RDONLY) {
|
|
error = EROFS;
|
|
goto out;
|
|
}
|
|
/* Make the node */
|
|
error = VOP_CREATE(dvp, name, &va, EXCL, 0, &vp, u.u_cred);
|
|
out:
|
|
/* Make response message */
|
|
make_response(sp, &in_bp, error, vp, &va, out_bp, outsize);
|
|
|
|
/* Free the request buffer (and the vnode if error) */
|
|
if (in_bp)
|
|
freemsg(in_bp);
|
|
if (vp)
|
|
VN_RELE(vp);
|
|
if (dvp)
|
|
VN_RELE(dvp);
|
|
|
|
DUPRINT4(DB_SERVE, "rs_mknod: result %d, name %s, vp %x\n",
|
|
error, name, vp);
|
|
return (error);
|
|
}
|
|
|
|
/*ARGSUSED*/
|
|
rs_chmod(sp, in_bp, out_bp, outsize, gift)
|
|
struct serv_proc *sp;
|
|
mblk_t *in_bp, **out_bp;
|
|
int *outsize;
|
|
rcvd_t *gift;
|
|
{
|
|
register struct request *msg_in;
|
|
register char *name;
|
|
struct vnode *vp = (struct vnode *) NULL;
|
|
struct vattr va;
|
|
int error = 0;
|
|
|
|
msg_in = (struct request *) PTOMSG(in_bp->b_rptr);
|
|
DUPRINT5(DB_SERVE, "rs_chmod: sp %x, name %s, mode %x, rd->vp %x\n",
|
|
sp, msg_in->rq_data, msg_in->rq_fmode, sp->s_rdp->rd_vnode);
|
|
|
|
/* Get file name and mode change from request message */
|
|
name = msg_in->rq_data;
|
|
vattr_null(&va);
|
|
va.va_mode = msg_in->rq_fmode & 07777;
|
|
|
|
/* Set the current working and root directories */
|
|
set_dir(sp->s_rdp, msg_in->rq_rrdir);
|
|
|
|
/* Get vnode for file to be chmod'ed */
|
|
if (error = rs_lookupname(name, UIOSEG_KERNEL, NO_FOLLOW, sp,
|
|
(struct vnode **) NULL, &vp))
|
|
goto out;
|
|
|
|
/* Can't change mode on read-only filesystems */
|
|
if (vp->v_vfsp->vfs_flag & VFS_RDONLY) {
|
|
error = EROFS;
|
|
goto out;
|
|
}
|
|
/* Change the mode */
|
|
error = VOP_SETATTR(vp, &va, u.u_cred);
|
|
out:
|
|
/* Make response message */
|
|
make_response(sp, &in_bp, error, (struct vnode *) NULL,
|
|
(struct vattr *) NULL, out_bp, outsize);
|
|
|
|
/* Free the request buffer (and the vnode if error) */
|
|
if (in_bp)
|
|
freemsg(in_bp);
|
|
if (vp)
|
|
VN_RELE(vp);
|
|
|
|
DUPRINT4(DB_SERVE, "rs_chmod: result %d, name %s, vp %x\n",
|
|
error, name, vp);
|
|
return (error);
|
|
}
|
|
|
|
/*ARGSUSED*/
|
|
rs_chown(sp, in_bp, out_bp, outsize, gift)
|
|
struct serv_proc *sp;
|
|
mblk_t *in_bp, **out_bp;
|
|
int *outsize;
|
|
rcvd_t *gift;
|
|
{
|
|
register struct request *msg_in;
|
|
register char *name;
|
|
struct vnode *vp = (struct vnode *) NULL;
|
|
struct vattr va;
|
|
int error = 0;
|
|
|
|
msg_in = (struct request *) PTOMSG(in_bp->b_rptr);
|
|
DUPRINT6(DB_SERVE, "rs_chown: sp %x, name %s, owner %d, group %d, rd->vp %x\n", sp, msg_in->rq_data, msg_in->rq_newuid, msg_in->rq_newgid, sp->s_rdp->rd_vnode);
|
|
|
|
/* Get file name and owner, group from request message */
|
|
name = msg_in->rq_data;
|
|
vattr_null(&va);
|
|
va.va_uid = gluid(sp->s_gdpp, (ushort) msg_in->rq_newuid);
|
|
va.va_gid = glgid(sp->s_gdpp, (ushort) msg_in->rq_newgid);
|
|
|
|
/* Set the current working and root directories */
|
|
set_dir(sp->s_rdp, msg_in->rq_rrdir);
|
|
|
|
/* Get vnode for file to be chown'ed */
|
|
if (error = rs_lookupname(name, UIOSEG_KERNEL, NO_FOLLOW, sp,
|
|
(struct vnode **) NULL, &vp))
|
|
goto out;
|
|
|
|
/* Can't change owner on read-only filesystems */
|
|
if (vp->v_vfsp->vfs_flag & VFS_RDONLY) {
|
|
error = EROFS;
|
|
goto out;
|
|
}
|
|
/* Change the mode */
|
|
error = VOP_SETATTR(vp, &va, u.u_cred);
|
|
out:
|
|
/* Make response message */
|
|
make_response(sp, &in_bp, error, (struct vnode *) NULL,
|
|
(struct vattr *) NULL, out_bp, outsize);
|
|
|
|
/* Free the request buffer (and the vnode if error) */
|
|
if (in_bp)
|
|
freemsg(in_bp);
|
|
if (vp)
|
|
VN_RELE(vp);
|
|
|
|
DUPRINT4(DB_SERVE, "rs_chown: result %d, name %s, vp %x\n",
|
|
error, name, vp);
|
|
return (error);
|
|
}
|
|
|
|
/*ARGSUSED*/
|
|
rs_stat(sp, in_bp, out_bp, outsize, gift)
|
|
struct serv_proc *sp;
|
|
mblk_t *in_bp, **out_bp;
|
|
int *outsize;
|
|
rcvd_t *gift;
|
|
{
|
|
register struct request *msg_in;
|
|
register struct response *msg_out;
|
|
register char *name;
|
|
long bufp;
|
|
struct vnode *vp = (struct vnode *) NULL;
|
|
struct rfs_stat *stp;
|
|
struct vattr va;
|
|
extern int rfsdev_pseudo();
|
|
int error = 0;
|
|
|
|
msg_in = (struct request *) PTOMSG(in_bp->b_rptr);
|
|
DUPRINT4(DB_SERVE, "rs_stat: sp %x, name %s, rd->vp %x\n",
|
|
sp, msg_in->rq_data, sp->s_rdp->rd_vnode);
|
|
|
|
/* Get syscall params: file name and client user buffer pointer */
|
|
name = msg_in->rq_data;
|
|
bufp = msg_in->rq_bufptr;
|
|
|
|
/* Set the current working and root directories */
|
|
set_dir(sp->s_rdp, msg_in->rq_rrdir);
|
|
|
|
/* Get vnode for file to be stat'ed */
|
|
if (error = rs_lookupname(name, UIOSEG_KERNEL, NO_FOLLOW, sp,
|
|
(struct vnode **) NULL, &vp))
|
|
goto out;
|
|
|
|
/* Get the file attributes */
|
|
error = VOP_GETATTR(vp, &va, u.u_cred);
|
|
|
|
/*
|
|
* Return EMFILE when inode is greater than 64k, more than a u_short
|
|
* can hold
|
|
*/
|
|
if (va.va_nodeid >= 0xfa00)
|
|
error = EMFILE;
|
|
|
|
out:
|
|
/* Make response message */
|
|
make_response(sp, &in_bp, error, (struct vnode *) NULL,
|
|
(struct vattr *) NULL, out_bp, outsize);
|
|
|
|
/* Put stat data into response */
|
|
if (!error) {
|
|
*outsize = sizeof (struct response) - DATASIZE +
|
|
sizeof (struct rfs_stat);
|
|
msg_out = (struct response *) PTOMSG((*out_bp)->b_rptr);
|
|
msg_out->rp_bufptr = bufp;
|
|
msg_out->rp_subyte = 0; /* Message contains data */
|
|
msg_out->rp_count = sizeof (struct rfs_stat);
|
|
stp = (struct rfs_stat *) msg_out->rp_data;
|
|
stp->st_mode = va.va_mode;
|
|
stp->st_uid = va.va_uid;
|
|
stp->st_gid = va.va_gid;
|
|
stat_rmap(sp->s_gdpp, stp);
|
|
/* Kludge up a dev# whose lower 8 bits are unique */
|
|
stp->st_dev = rfsdev_pseudo((short) va.va_fsid);
|
|
stp->st_ino = va.va_nodeid;
|
|
stp->st_nlink = va.va_nlink;
|
|
stp->st_size = va.va_size;
|
|
stp->st_atime = va.va_atime.tv_sec + sp->s_gdpp->time;
|
|
stp->st_mtime = va.va_mtime.tv_sec + sp->s_gdpp->time;
|
|
stp->st_ctime = va.va_ctime.tv_sec + sp->s_gdpp->time;
|
|
stp->st_rdev = (dev_t)va.va_rdev;
|
|
}
|
|
/* Free the request buffer and the vnode */
|
|
if (in_bp)
|
|
freemsg(in_bp);
|
|
if (vp)
|
|
VN_RELE(vp);
|
|
|
|
DUPRINT4(DB_SERVE, "rs_stat: result %d, name %s, vp %x\n",
|
|
error, name, vp);
|
|
return (error);
|
|
}
|
|
|
|
/*
|
|
* Remote seek -- only gets called if seek is re end of file. Only job
|
|
* is to return current file size.
|
|
*/
|
|
/*ARGSUSED*/
|
|
rs_seek(sp, in_bp, out_bp, outsize, gift)
|
|
struct serv_proc *sp;
|
|
mblk_t *in_bp, **out_bp;
|
|
int *outsize;
|
|
rcvd_t *gift;
|
|
{
|
|
register struct response *msg_out;
|
|
struct vnode *vp = (struct vnode *) NULL;
|
|
struct vattr va;
|
|
int error = 0;
|
|
|
|
DUPRINT3(DB_SERVE, "rs_seek: sp %x, rd->vp %x\n", sp,
|
|
sp->s_rdp->rd_vnode);
|
|
|
|
freemsg(in_bp);
|
|
vp = sp->s_rdp->rd_vnode;
|
|
|
|
/* Get the file attributes */
|
|
error = VOP_GETATTR(vp, &va, u.u_cred);
|
|
|
|
/* Make response message */
|
|
make_response(sp, (mblk_t **) NULL, error, (struct vnode *) NULL,
|
|
(struct vattr *) NULL, out_bp, outsize);
|
|
|
|
/* Return file size */
|
|
if (!error) {
|
|
msg_out = (struct response *) PTOMSG((*out_bp)->b_rptr);
|
|
msg_out->rp_rval = va.va_size;
|
|
}
|
|
DUPRINT3(DB_SERVE, "rs_seek: result %d size %d\n", error, va.va_size);
|
|
return (error);
|
|
}
|
|
|
|
/*ARGSUSED*/
|
|
rs_fstat(sp, in_bp, out_bp, outsize, gift)
|
|
struct serv_proc *sp;
|
|
mblk_t *in_bp, **out_bp;
|
|
int *outsize;
|
|
rcvd_t *gift;
|
|
{
|
|
register struct request *msg_in;
|
|
register struct response *msg_out;
|
|
extern int rfsdev_pseudo();
|
|
long bufp;
|
|
struct vnode *vp = (struct vnode *) NULL;
|
|
struct vattr va;
|
|
struct rfs_stat *stp;
|
|
int error = 0;
|
|
|
|
msg_in = (struct request *) PTOMSG(in_bp->b_rptr);
|
|
DUPRINT3(DB_SERVE, "rs_fstat: sp %x, rd->vp %x\n", sp,
|
|
sp->s_rdp->rd_vnode);
|
|
|
|
/* Get syscall params: client user buffer pointer and vnode */
|
|
bufp = msg_in->rq_bufptr;
|
|
vp = sp->s_rdp->rd_vnode;
|
|
|
|
/* Get the file attributes */
|
|
error = VOP_GETATTR(vp, &va, u.u_cred);
|
|
|
|
#define FLAG 1
|
|
#ifdef FLAG
|
|
/*
|
|
* Return EMFILE when inode is greater than 64k, more than a u_short
|
|
* can hold
|
|
*/
|
|
if (va.va_nodeid >= 0xfa00)
|
|
error = EMFILE;
|
|
#endif
|
|
|
|
/* Make response message */
|
|
make_response(sp, &in_bp, error, (struct vnode *) NULL,
|
|
(struct vattr *) NULL, out_bp, outsize);
|
|
|
|
/* Put stat data into response */
|
|
if (!error) {
|
|
*outsize = sizeof (struct response) - DATASIZE +
|
|
sizeof (struct rfs_stat);
|
|
msg_out = (struct response *) PTOMSG((*out_bp)->b_rptr);
|
|
msg_out->rp_bufptr = bufp;
|
|
msg_out->rp_subyte = 0; /* Message contains data */
|
|
msg_out->rp_count = sizeof (struct rfs_stat);
|
|
stp = (struct rfs_stat *) msg_out->rp_data;
|
|
stp->st_mode = va.va_mode;
|
|
stp->st_uid = va.va_uid;
|
|
stp->st_gid = va.va_gid;
|
|
stat_rmap(sp->s_gdpp, stp);
|
|
/* Kludge up a dev# whose lower 8 bits are unique */
|
|
stp->st_dev = rfsdev_pseudo((short) va.va_fsid);
|
|
stp->st_ino = va.va_nodeid;
|
|
stp->st_nlink = va.va_nlink;
|
|
stp->st_size = va.va_size;
|
|
stp->st_atime = va.va_atime.tv_sec + sp->s_gdpp->time;
|
|
stp->st_mtime = va.va_mtime.tv_sec + sp->s_gdpp->time;
|
|
stp->st_ctime = va.va_ctime.tv_sec + sp->s_gdpp->time;
|
|
stp->st_rdev = (dev_t)va.va_rdev;
|
|
}
|
|
|
|
/* Free the request buffer */
|
|
if (in_bp)
|
|
freemsg(in_bp);
|
|
|
|
DUPRINT3(DB_SERVE, "rs_fstat: result %d, vp %x\n",
|
|
error, vp);
|
|
return (error);
|
|
}
|
|
|
|
/*ARGSUSED*/
|
|
rs_utime(sp, in_bp, out_bp, outsize, gift)
|
|
struct serv_proc *sp;
|
|
mblk_t *in_bp, **out_bp;
|
|
int *outsize;
|
|
rcvd_t *gift;
|
|
{
|
|
register struct request *msg_in;
|
|
register struct response *msg_out;
|
|
register char *name;
|
|
struct vnode *vp = (struct vnode *) NULL;
|
|
struct vattr va;
|
|
struct rfs_utimbuf *tp;
|
|
extern struct timeval time;
|
|
mblk_t *data_bp, *go_bp;
|
|
struct response *data_msg;
|
|
long bufp;
|
|
rcvd_t rd = (rcvd_t) NULL;
|
|
int no_sig = 1;
|
|
int rs;
|
|
int error = 0;
|
|
|
|
msg_in = (struct request *) PTOMSG(in_bp->b_rptr);
|
|
DUPRINT5(DB_SERVE, "rs_utime: sp %x, name %s, bufp %x, rd->vp %x\n",
|
|
sp, msg_in->rq_data, msg_in->rq_bufptr, sp->s_rdp->rd_vnode);
|
|
|
|
/* Get file name and client user time buffer pointer */
|
|
name = msg_in->rq_data;
|
|
bufp = msg_in->rq_bufptr;
|
|
vattr_null(&va);
|
|
|
|
/* Use local current time or get from client if specified */
|
|
if (!bufp) {
|
|
va.va_mtime.tv_sec = time.tv_sec;
|
|
va.va_mtime.tv_usec = -1;
|
|
} else {
|
|
/* Create rd on which to receive time values */
|
|
if ((rd = cr_rcvd(FILE_QSIZE, SPECIFIC)) == (rcvd_t) NULL) {
|
|
error = ENOMEM;
|
|
goto out;
|
|
}
|
|
rd->rd_sd = sp->s_sdp;
|
|
rd->rd_qsize = SIGQSIZE;
|
|
|
|
/* Send back go-ahead message */
|
|
go_bp = salocbuf(sizeof (struct response), BPRI_MED);
|
|
msg_out = (struct response *)PTOMSG(go_bp->b_rptr);
|
|
msg_out->rp_type = RESP_MSG;
|
|
msg_out->rp_opcode = DUCOPYIN;
|
|
msg_out->rp_errno = 0;
|
|
msg_out->rp_bufptr = bufp;
|
|
msg_out->rp_bp = (long) go_bp;
|
|
msg_out->rp_count = sizeof (struct rfs_utimbuf);
|
|
if (error = sndmsg(sp->s_sdp, go_bp,
|
|
sizeof (struct response) - DATASIZE, rd)) {
|
|
free_rcvd(rd);
|
|
goto out;
|
|
}
|
|
|
|
/* Get back times */
|
|
error = de_queue(rd, &data_bp, (sndd_t)NULL, &rs, &no_sig,
|
|
(sndd_t)NULL);
|
|
free_rcvd(rd);
|
|
if (error)
|
|
goto out;
|
|
data_msg = (struct response *)PTOMSG(data_bp->b_rptr);
|
|
if (data_msg->rp_errno) {
|
|
error = RFSTOERR(data_msg->rp_errno);
|
|
freemsg(data_bp);
|
|
goto out;
|
|
}
|
|
if (sp->s_gdpp->hetero != NO_CONV)
|
|
(void) fcanon(rfs_utimbuf, data_msg->rp_data,
|
|
data_msg->rp_data);
|
|
tp = (struct rfs_utimbuf *) data_msg->rp_data;
|
|
vattr_null(&va);
|
|
/* Adjust to local time */
|
|
va.va_atime.tv_sec = tp->ut_actime - sp->s_gdpp->time;
|
|
va.va_mtime.tv_sec = tp->ut_modtime - sp->s_gdpp->time;
|
|
va.va_atime.tv_usec = 0;
|
|
va.va_mtime.tv_usec = 0;
|
|
freemsg(data_bp);
|
|
|
|
DUPRINT3(DB_SERVE, "rs_utime: times %d %d\n",
|
|
va.va_atime.tv_sec, va.va_mtime.tv_sec);
|
|
}
|
|
|
|
/* Set the current working and root directories */
|
|
set_dir(sp->s_rdp, msg_in->rq_rrdir);
|
|
|
|
/* Get vnode for file whose times are to be changed */
|
|
if (error = rs_lookupname(name, UIOSEG_KERNEL, NO_FOLLOW, sp,
|
|
(struct vnode **) NULL, &vp))
|
|
goto out;
|
|
|
|
/* Can't change attributes on read-only filesystems */
|
|
if (vp->v_vfsp->vfs_flag & VFS_RDONLY) {
|
|
error = EROFS;
|
|
goto out;
|
|
}
|
|
/* Change the time */
|
|
error = VOP_SETATTR(vp, &va, u.u_cred);
|
|
out:
|
|
/* Make response message */
|
|
make_response(sp, &in_bp, error, (struct vnode *) NULL,
|
|
(struct vattr *) NULL, out_bp, outsize);
|
|
|
|
/* Free the request buffer (and the vnode if error) */
|
|
if (in_bp)
|
|
freemsg(in_bp);
|
|
if (vp)
|
|
VN_RELE(vp);
|
|
|
|
DUPRINT4(DB_SERVE, "rs_utime: result %d, name %s, vp %x\n",
|
|
error, name, vp);
|
|
return (error);
|
|
}
|
|
|
|
|
|
/*ARGSUSED*/
|
|
rs_access(sp, in_bp, out_bp, outsize, gift)
|
|
struct serv_proc *sp;
|
|
mblk_t *in_bp, **out_bp;
|
|
int *outsize;
|
|
rcvd_t *gift;
|
|
{
|
|
register struct request *msg_in;
|
|
register char *name;
|
|
struct vnode *vp = (struct vnode *) NULL;
|
|
u_short mode;
|
|
int error = 0;
|
|
|
|
msg_in = (struct request *) PTOMSG(in_bp->b_rptr);
|
|
DUPRINT5(DB_SERVE, "rs_access: sp %x, name %s, mode %x, rd->vp %x\n",
|
|
sp, msg_in->rq_data, msg_in->rq_fmode, sp->s_rdp->rd_vnode);
|
|
|
|
/* Get file name and access mode from request message */
|
|
name = msg_in->rq_data;
|
|
mode = RFSTOVACC(msg_in->rq_fmode);
|
|
|
|
/* Set the current working and root directories */
|
|
set_dir(sp->s_rdp, msg_in->rq_rrdir);
|
|
|
|
/* Get vnode for file to be accessed */
|
|
if (error = rs_lookupname(name, UIOSEG_KERNEL, NO_FOLLOW, sp,
|
|
(struct vnode **) NULL, &vp))
|
|
goto out;
|
|
|
|
/* No write access to read-only filesystems */
|
|
if ((mode & VWRITE) && (vp->v_vfsp->vfs_flag & VFS_RDONLY)) {
|
|
error = EROFS;
|
|
goto out;
|
|
}
|
|
/* Do the access */
|
|
error = VOP_ACCESS(vp, mode, u.u_cred);
|
|
out:
|
|
/* Make response message */
|
|
make_response(sp, &in_bp, error, (struct vnode *) NULL,
|
|
(struct vattr *) NULL, out_bp, outsize);
|
|
|
|
/* Free the request buffer and the vnode */
|
|
if (in_bp)
|
|
freemsg(in_bp);
|
|
if (vp)
|
|
VN_RELE(vp);
|
|
|
|
DUPRINT4(DB_SERVE, "rs_access: result %d, name %s, vp %x\n",
|
|
error, name, vp);
|
|
return (error);
|
|
}
|
|
|
|
|
|
/*ARGSUSED*/
|
|
rs_statfs(sp, in_bp, out_bp, outsize, gift)
|
|
struct serv_proc *sp;
|
|
mblk_t *in_bp, **out_bp;
|
|
int *outsize;
|
|
rcvd_t *gift;
|
|
{
|
|
register struct request *msg_in;
|
|
register struct response *msg_out;
|
|
register char *name;
|
|
long bufp, len, fstyp;
|
|
struct vnode *vp = (struct vnode *) NULL;
|
|
register struct rfs_statfs *stp;
|
|
struct statfs sb;
|
|
int error = 0;
|
|
|
|
msg_in = (struct request *) PTOMSG(in_bp->b_rptr);
|
|
|
|
DUPRINT6(DB_SERVE,
|
|
"rs_statfs: sp %x, name %x, bufp %x, len %d, rd->vp %x\n",
|
|
sp, msg_in->rq_data, msg_in->rq_bufptr, msg_in->rq_len,
|
|
sp->s_rdp->rd_vnode);
|
|
|
|
/*
|
|
* Get syscall params: file name, client user buffer pointer, length
|
|
* of data to be returned, file system type
|
|
*/
|
|
name = msg_in->rq_data;
|
|
bufp = msg_in->rq_bufptr;
|
|
len = msg_in->rq_len;
|
|
fstyp = msg_in->rq_fstyp;
|
|
|
|
/*
|
|
* Client must have right length. Note: this is not a particularly
|
|
* meaningful value as it refers to the size of a data structure whose
|
|
* size may vary from machine to machine.
|
|
*/
|
|
if (len < 0) {
|
|
error = EINVAL;
|
|
goto out;
|
|
}
|
|
/*
|
|
* Only support mounted filesystems (fstyp = 0, and name is name
|
|
* of file in filesystem to statfs'ed)
|
|
*/
|
|
if (fstyp) {
|
|
error = EINVAL;
|
|
goto out;
|
|
}
|
|
/* Set the current working and root directories */
|
|
set_dir(sp->s_rdp, msg_in->rq_rrdir);
|
|
|
|
/* Get vnode for file to be statfs'ed */
|
|
if (error = rs_lookupname(name, UIOSEG_KERNEL, NO_FOLLOW, sp,
|
|
(struct vnode **) NULL, &vp))
|
|
goto out;
|
|
|
|
error = VFS_STATFS(vp->v_vfsp, &sb);
|
|
out:
|
|
/* Make response message */
|
|
make_response(sp, &in_bp, error, (struct vnode *) NULL,
|
|
(struct vattr *) NULL, out_bp, outsize);
|
|
|
|
/* Put statfs data into response */
|
|
if (!error) {
|
|
*outsize = sizeof (struct response) - DATASIZE +
|
|
sizeof (struct rfs_statfs);
|
|
msg_out = (struct response *) PTOMSG((*out_bp)->b_rptr);
|
|
msg_out->rp_bufptr = bufp;
|
|
msg_out->rp_subyte = 0; /* Message contains data */
|
|
msg_out->rp_count = sizeof (struct rfs_statfs);
|
|
stp = (struct rfs_statfs *) msg_out->rp_data;
|
|
stp->f_fstyp = 0; /* Not a meaningful value */
|
|
stp->f_bsize = sb.f_bsize;
|
|
stp->f_frsize = 0;
|
|
stp->f_blocks = sb.f_blocks;
|
|
stp->f_bfree = sb.f_bfree;
|
|
stp->f_files = sb.f_files;
|
|
stp->f_ffree = sb.f_ffree;
|
|
stp->f_fname[0] = '\0';
|
|
stp->f_fpack[0] = '\0';
|
|
}
|
|
|
|
/* Free the request buffer and the vnode */
|
|
if (in_bp)
|
|
freemsg(in_bp);
|
|
if (vp)
|
|
VN_RELE(vp);
|
|
|
|
DUPRINT4(DB_SERVE, "rs_statfs: result %d, name %s, vp %x\n",
|
|
error, name, vp);
|
|
return (error);
|
|
}
|
|
|
|
/*ARGSUSED*/
|
|
rs_fstatfs(sp, in_bp, out_bp, outsize, gift)
|
|
struct serv_proc *sp;
|
|
mblk_t *in_bp, **out_bp;
|
|
int *outsize;
|
|
rcvd_t *gift;
|
|
{
|
|
register struct request *msg_in;
|
|
register struct response *msg_out;
|
|
long bufp, len, fstyp;
|
|
struct vnode *vp = (struct vnode *) NULL;
|
|
struct rfs_statfs *stp;
|
|
struct statfs sb;
|
|
int error = 0;
|
|
|
|
msg_in = (struct request *) PTOMSG(in_bp->b_rptr);
|
|
DUPRINT6(DB_SERVE,
|
|
"rs_fstatfs: sp %x, bufp %x, len %d, fstyp %d, rd->vp %x\n",
|
|
sp, msg_in->rq_bufptr, msg_in->rq_len, msg_in->rq_fstyp,
|
|
sp->s_rdp->rd_vnode);
|
|
|
|
/*
|
|
* Get syscall params: client user buffer pointer, length
|
|
* of data to be returned, file system type, vnode
|
|
*/
|
|
bufp = msg_in->rq_bufptr;
|
|
len = msg_in->rq_len;
|
|
fstyp = msg_in->rq_fstyp;
|
|
vp = sp->s_rdp->rd_vnode;
|
|
|
|
/*
|
|
* Client must have right length. Note: this is not a particularly
|
|
* meaningful value as it refers to the size of a data structure whose
|
|
* size may vary from machine to machine.
|
|
*/
|
|
if (len < 0) {
|
|
error = EINVAL;
|
|
goto out;
|
|
}
|
|
/*
|
|
* Only support mounted filesystems (fstyp = 0 and vnode is in
|
|
* filesystem to statfs)
|
|
*/
|
|
if (fstyp) {
|
|
error = EINVAL;
|
|
goto out;
|
|
}
|
|
/* Get the statfs info */
|
|
error = VFS_STATFS(vp->v_vfsp, &sb);
|
|
out:
|
|
/* Make response message */
|
|
make_response(sp, &in_bp, error, (struct vnode *) NULL,
|
|
(struct vattr *) NULL, out_bp, outsize);
|
|
|
|
/* Put statfs data into response */
|
|
if (!error) {
|
|
*outsize = sizeof (struct response) - DATASIZE +
|
|
sizeof (struct rfs_statfs);
|
|
msg_out = (struct response *) PTOMSG((*out_bp)->b_rptr);
|
|
msg_out->rp_bufptr = bufp;
|
|
msg_out->rp_subyte = 0; /* Message contains data */
|
|
msg_out->rp_count = sizeof (struct rfs_statfs);
|
|
stp = (struct rfs_statfs *) msg_out->rp_data;
|
|
stp->f_fstyp = sb.f_type;
|
|
stp->f_bsize = sb.f_bsize;
|
|
stp->f_frsize = 0;
|
|
stp->f_blocks = sb.f_blocks;
|
|
stp->f_bfree = sb.f_bfree;
|
|
stp->f_files = sb.f_files;
|
|
stp->f_ffree = sb.f_ffree;
|
|
stp->f_fname[0] = '\0';
|
|
stp->f_fpack[0] = '\0';
|
|
}
|
|
|
|
/* Free the request buffer */
|
|
if (in_bp)
|
|
freemsg(in_bp);
|
|
DUPRINT2(DB_SERVE, "rs_fstatfs: result %d\n",
|
|
error);
|
|
return (error);
|
|
}
|
|
|
|
/*ARGSUSED*/
|
|
rs_ioctl(sp, in_bp, out_bp, outsize, gift)
|
|
struct serv_proc *sp;
|
|
mblk_t *in_bp, **out_bp;
|
|
int *outsize;
|
|
rcvd_t *gift;
|
|
{
|
|
register struct request *msg_in;
|
|
register struct response *msg_out;
|
|
struct vnode *vp = (struct vnode *) NULL;
|
|
long cmd, arg, flag;
|
|
int size;
|
|
char data[_IOCPARM_MASK+1];
|
|
mblk_t *data_bp, *go_bp;
|
|
struct response *data_msg;
|
|
rcvd_t rd = (rcvd_t) NULL;
|
|
int no_sig = 1;
|
|
int rs;
|
|
int msgsz;
|
|
int error = 0;
|
|
|
|
msg_in = (struct request *) PTOMSG(in_bp->b_rptr);
|
|
DUPRINT6(DB_SERVE,
|
|
"rs_ioctl: sp %x, cmd %x, arg %x, flag %x, rd->vp %x\n",
|
|
sp, msg_in->rq_cmd, msg_in->rq_ioarg, msg_in->rq_fflag,
|
|
sp->s_rdp->rd_vnode);
|
|
/*
|
|
* Can only do ioctl between homogeneous machines, since you
|
|
* don't know what data elements are in the ioctl args
|
|
*/
|
|
if (sp->s_gdpp->hetero != NO_CONV) {
|
|
freemsg(in_bp);
|
|
error = EINVAL;
|
|
goto out;
|
|
}
|
|
/* Get syscall params: cmd, arg, flag */
|
|
cmd = msg_in->rq_cmd;
|
|
arg = msg_in->rq_ioarg;
|
|
flag = msg_in->rq_fflag;
|
|
size = (cmd &~ (_IOC_INOUT|_IOC_VOID)) >> 16;
|
|
vp = sp->s_rdp->rd_vnode;
|
|
|
|
/* Set client remote signal, if any */
|
|
setrsig(sp, in_bp);
|
|
freemsg(in_bp);
|
|
|
|
/* Recover if system call is interrupted */
|
|
if (setjmp(&u.u_qsave)) {
|
|
error = EINTR;
|
|
goto out;
|
|
}
|
|
/* If data is to come in, get it (DUCOPYIN) */
|
|
if (cmd & _IOC_IN) {
|
|
/* Create rd on which to receive data */
|
|
if ((rd = cr_rcvd(FILE_QSIZE, SPECIFIC)) == (rcvd_t) NULL) {
|
|
error = ENOMEM;
|
|
goto out;
|
|
}
|
|
rd->rd_sd = sp->s_sdp;
|
|
rd->rd_qsize = SIGQSIZE;
|
|
|
|
/* Send back go-ahead message */
|
|
go_bp = salocbuf(sizeof (struct response), BPRI_MED);
|
|
msg_out = (struct response *)PTOMSG(go_bp->b_rptr);
|
|
msg_out->rp_type = RESP_MSG;
|
|
msg_out->rp_opcode = DUCOPYIN;
|
|
msg_out->rp_bufptr = arg;
|
|
msg_out->rp_bp = (long) go_bp;
|
|
msg_out->rp_count = size;
|
|
msg_out->rp_errno = 0;
|
|
if (error = sndmsg(sp->s_sdp, go_bp,
|
|
sizeof (struct response) - DATASIZE, rd)) {
|
|
free_rcvd(rd);
|
|
goto out;
|
|
}
|
|
/* Get back data */
|
|
error = de_queue(rd, &data_bp, (sndd_t)NULL, &rs, &no_sig,
|
|
(sndd_t)NULL);
|
|
free_rcvd(rd);
|
|
if (error)
|
|
goto out;
|
|
data_msg = (struct response *)PTOMSG(data_bp->b_rptr);
|
|
if (data_msg->rp_errno) {
|
|
error = RFSTOERR(data_msg->rp_errno);
|
|
freemsg(data_bp);
|
|
goto out;
|
|
}
|
|
ASSERT(size == data_msg->rp_count);
|
|
bcopy((caddr_t) data_msg->rp_data, (caddr_t) data, (u_int) size);
|
|
freemsg(data_bp);
|
|
DUPRINT5(DB_SERVE, "rs_ioctl: DUCOPYIN data: %x %x %x %x %x\n",
|
|
(unsigned *) data[0], (unsigned *) data[1],
|
|
(unsigned *) data[2], (unsigned *) data[3]);
|
|
}
|
|
|
|
/* Do the ioctl */
|
|
error = VOP_IOCTL(vp, cmd, data, flag, u.u_cred);
|
|
|
|
/* If data is to go out, send it out (DUCOPYOUT) */
|
|
if (cmd & _IOC_OUT) {
|
|
data_bp = salocbuf(sizeof (struct response), BPRI_MED);
|
|
msg_out = (struct response *)PTOMSG(data_bp->b_rptr);
|
|
msg_out->rp_type = RESP_MSG;
|
|
msg_out->rp_opcode = DUCOPYOUT;
|
|
msg_out->rp_bufptr = arg;
|
|
msg_out->rp_bp = (long) data_bp;
|
|
msg_out->rp_subyte = 0; /* Message contains data */
|
|
msg_out->rp_count = size;
|
|
msgsz = sizeof (struct response) - DATASIZE + size;
|
|
msg_out->rp_copysync = 0;
|
|
msg_out->rp_errno = 0;
|
|
bcopy(data, (caddr_t) msg_out->rp_data, (u_int) size);
|
|
error = sndmsg(sp->s_sdp, data_bp, msgsz, (rcvd_t) NULL);
|
|
DUPRINT5(DB_SERVE, "rs_ioctl: DUCOPYOUT data: %x %x %x %x\n",
|
|
(unsigned *) data[0], (unsigned *) data[1],
|
|
(unsigned *) data[2], (unsigned *) data[3]);
|
|
}
|
|
out:
|
|
chkrsig(sp, &error);
|
|
|
|
/* Make response message */
|
|
make_response(sp, (mblk_t **) NULL, error, (struct vnode *) NULL,
|
|
(struct vattr *) NULL, out_bp, outsize);
|
|
|
|
DUPRINT3(DB_SERVE, "rs_ioctl: result %d, vp %x\n",
|
|
error, vp);
|
|
return (error);
|
|
}
|
|
|
|
/*ARGSUSED*/
|
|
rs_utssys(sp, in_bp, out_bp, outsize, gift)
|
|
struct serv_proc *sp;
|
|
mblk_t *in_bp, **out_bp;
|
|
int *outsize;
|
|
rcvd_t *gift;
|
|
{
|
|
register struct request *msg_in;
|
|
register struct response *msg_out;
|
|
struct statfs sb;
|
|
struct rfs_ustat *rsb;
|
|
struct vfs *vfs;
|
|
long dev;
|
|
long bufp;
|
|
int error = 0;
|
|
short rfsdev_real();
|
|
|
|
msg_in = (struct request *) PTOMSG(in_bp->b_rptr);
|
|
DUPRINT4(DB_SERVE, "rs_utssys: sp %x, dev %x, bufp %x\n",
|
|
sp, msg_in->rq_dev, msg_in->rq_bufptr);
|
|
|
|
dev = msg_in->rq_dev;
|
|
bufp = msg_in->rq_bufptr;
|
|
|
|
/* Get the vfs corresponding to this device number */
|
|
if (error = vafsidtovfs((long) rfsdev_real((int) dev) & 0x0ffff, &vfs))
|
|
goto out;
|
|
|
|
/* Statfs the filesystem */
|
|
if (error = VFS_STATFS(vfs, &sb))
|
|
goto out;
|
|
out:
|
|
/* Make response message */
|
|
make_response(sp, &in_bp, error, (struct vnode *) NULL,
|
|
(struct vattr *) NULL, out_bp, outsize);
|
|
|
|
/* Put statfs data into response */
|
|
if (!error) {
|
|
*outsize = sizeof (struct response) - DATASIZE +
|
|
sizeof (struct rfs_ustat);
|
|
msg_out = (struct response *) PTOMSG((*out_bp)->b_rptr);
|
|
msg_out->rp_bufptr = bufp;
|
|
msg_out->rp_subyte = 0; /* Message contains data */
|
|
msg_out->rp_count = sizeof (struct rfs_ustat);
|
|
rsb = (struct rfs_ustat *) msg_out->rp_data;
|
|
rsb->f_tfree = sb.f_bavail * (sb.f_bsize / DEV_BSIZE);
|
|
rsb->f_tinode = sb.f_ffree;
|
|
bzero((caddr_t)rsb->f_fname, 6);
|
|
bzero((caddr_t)rsb->f_fpack, 6);
|
|
}
|
|
|
|
/* Free the request buffer and the vnode */
|
|
if (in_bp)
|
|
freemsg(in_bp);
|
|
|
|
DUPRINT3(DB_SERVE, "rs_utssys: result %d, free blocks %d\n",
|
|
error, error ? 0 : rsb->f_tfree);
|
|
return (error);
|
|
}
|
|
|
|
rs_chdir(sp, in_bp, out_bp, outsize, gift)
|
|
struct serv_proc *sp;
|
|
mblk_t *in_bp, **out_bp;
|
|
int *outsize;
|
|
rcvd_t *gift;
|
|
{
|
|
register struct request *msg_in;
|
|
register char *name;
|
|
struct vnode *vp = (struct vnode *) NULL;
|
|
int error = 0;
|
|
struct vattr va;
|
|
|
|
msg_in = (struct request *) PTOMSG(in_bp->b_rptr);
|
|
DUPRINT4(DB_SERVE, "rs_chdir: sp %x, name %s, rd->vp %x\n",
|
|
sp, msg_in->rq_data, sp->s_rdp->rd_vnode);
|
|
|
|
/* Get file name and access mode from request message */
|
|
name = msg_in->rq_data;
|
|
|
|
/* Set the current working and root directories */
|
|
set_dir(sp->s_rdp, msg_in->rq_rrdir);
|
|
|
|
/* Get vnode for directory to be chroot'ed to */
|
|
if (error = rs_lookupname(name, UIOSEG_KERNEL, NO_FOLLOW, sp,
|
|
(struct vnode **) NULL, &vp))
|
|
goto out;
|
|
|
|
/* Must be a directory */
|
|
if (vp->v_type != VDIR) {
|
|
error = ENOTDIR;
|
|
goto out;
|
|
}
|
|
/* Must have x access */
|
|
if (error = VOP_ACCESS(vp, VEXEC, u.u_cred))
|
|
goto out;
|
|
|
|
/* Get attributes of new vnode to return to client */
|
|
if (error = VOP_GETATTR(vp, &va, u.u_cred))
|
|
goto out;
|
|
|
|
/* Make a receive descriptor for client requests on new vnode */
|
|
if (error = make_gift(vp, FILE_QSIZE, sp, gift))
|
|
goto out;
|
|
srmount[sp->s_mntindx].sr_refcnt++; /* New ref on this mnt point */
|
|
out:
|
|
/* Make response message */
|
|
make_response(sp, &in_bp, error, vp, &va, out_bp, outsize);
|
|
|
|
/* Free the request buffer (and the vnode if error) */
|
|
if (in_bp)
|
|
freemsg(in_bp);
|
|
if (error) {
|
|
if (vp)
|
|
VN_RELE(vp);
|
|
}
|
|
DUPRINT4(DB_SERVE, "rs_chdir: result %d, name %s, vp %x\n",
|
|
error, name, vp);
|
|
return (error);
|
|
}
|
|
|
|
/*ARGSUSED*/
|
|
rs_fcntl(sp, in_bp, out_bp, outsize, gift)
|
|
struct serv_proc *sp;
|
|
mblk_t *in_bp, **out_bp;
|
|
int *outsize;
|
|
rcvd_t *gift;
|
|
{
|
|
register struct request *msg_in;
|
|
register struct response *msg_out;
|
|
struct vnode *vp = (struct vnode *) NULL;
|
|
long cmd, arg, flag;
|
|
struct file ff;
|
|
int size;
|
|
struct flock ld;
|
|
mblk_t *data_bp, *go_bp;
|
|
struct response *data_msg;
|
|
rcvd_t rd = (rcvd_t) NULL;
|
|
int no_sig = 1;
|
|
int rs, s;
|
|
int msgsz;
|
|
int error = 0;
|
|
int frcache;
|
|
|
|
msg_in = (struct request *) PTOMSG(in_bp->b_rptr);
|
|
DUPRINT6(DB_SERVE, "rs_fcntl: sp %x, cmd %x, foffset %x, flag %x, rd->vp %x\n", sp, msg_in->rq_cmd, msg_in->rq_foffset, msg_in->rq_fflag, sp->s_rdp->rd_vnode);
|
|
|
|
/* Get syscall params: cmd, arg, flag */
|
|
s = splrf();
|
|
cmd = RFSTOFCNTL(msg_in->rq_cmd);
|
|
flag = msg_in->rq_fflag;
|
|
frcache = (flag & RFS_FRCACH);
|
|
flag &= ~RFS_FRCACH;
|
|
flag = RFSTOFFLAG(flag);
|
|
arg = msg_in->rq_fcntl;
|
|
size = sizeof (struct rfs_flock);
|
|
vp = sp->s_rdp->rd_vnode;
|
|
ff.f_offset = msg_in->rq_foffset;
|
|
ff.f_data = (caddr_t) vp;
|
|
|
|
/* Set client remote signal, if any */
|
|
setrsig(sp, in_bp);
|
|
if (!frcache)
|
|
freemsg(in_bp);
|
|
|
|
|
|
/* Recover if system call is interrupted */
|
|
if (setjmp(&u.u_qsave)) {
|
|
error = EINTR;
|
|
goto out;
|
|
}
|
|
/* Check for valid command */
|
|
if (cmd != F_GETLK && cmd != F_SETLK &&
|
|
cmd != F_SETLKW && cmd != F_CHKFL && cmd != F_FREESP) {
|
|
error = EINVAL;
|
|
goto out;
|
|
}
|
|
/* Not supported */
|
|
if (cmd == F_FREESP) {
|
|
error = EINVAL;
|
|
goto out;
|
|
}
|
|
/*
|
|
* Check file flags for validity of requested changes --
|
|
* S5R3 does nothing
|
|
*/
|
|
if (cmd == F_CHKFL) {
|
|
goto out;
|
|
}
|
|
|
|
/* If lock structure is to come in, get it */
|
|
if (cmd == F_GETLK || cmd == F_SETLK || cmd == F_SETLKW ||
|
|
cmd == F_CHKFL) {
|
|
/* New (5.3.1) style -- pass lock req. with fcntl call */
|
|
if (frcache) {
|
|
if (msg_in->rq_prewrite > 0) {
|
|
bcopy((caddr_t) msg_in->rq_data, (caddr_t) &ld,
|
|
(u_int) size);
|
|
freemsg(in_bp);
|
|
}
|
|
/* Old style (DUCOPYIN) */
|
|
} else {
|
|
/* Create rd on which to receive data */
|
|
if ((rd = cr_rcvd(FILE_QSIZE, SPECIFIC))
|
|
== (rcvd_t) NULL) {
|
|
error = ENOMEM;
|
|
goto out;
|
|
}
|
|
rd->rd_sd = sp->s_sdp;
|
|
rd->rd_qsize = SIGQSIZE;
|
|
|
|
/* Send back go-ahead message */
|
|
go_bp = salocbuf(sizeof (struct response), BPRI_MED);
|
|
msg_out = (struct response *)PTOMSG(go_bp->b_rptr);
|
|
msg_out->rp_type = RESP_MSG;
|
|
msg_out->rp_opcode = DUCOPYIN;
|
|
msg_out->rp_bufptr = arg;
|
|
msg_out->rp_bp = (long) go_bp;
|
|
msg_out->rp_count = size;
|
|
msg_out->rp_errno = 0;
|
|
if (error = sndmsg(sp->s_sdp, go_bp,
|
|
sizeof (struct response) - DATASIZE, rd)) {
|
|
free_rcvd(rd);
|
|
goto out;
|
|
}
|
|
/* Get back data */
|
|
error = de_queue(rd, &data_bp, (sndd_t)NULL, &rs,
|
|
&no_sig, (sndd_t)NULL);
|
|
free_rcvd(rd);
|
|
if (error)
|
|
goto out;
|
|
data_msg = (struct response *)PTOMSG(data_bp->b_rptr);
|
|
if (data_msg->rp_errno) {
|
|
error = RFSTOERR(data_msg->rp_errno);
|
|
freemsg(data_bp);
|
|
goto out;
|
|
}
|
|
ASSERT(size == data_msg->rp_count);
|
|
bcopy((caddr_t) data_msg->rp_data, (caddr_t) &ld,
|
|
(u_int) size);
|
|
freemsg(data_bp);
|
|
DUPRINT6(DB_SERVE, "rs_fcntl: DUCOPYIN: type %x, whence %x, start %x, len %x, pid %x\n", ld.l_type, ld.l_whence, ld.l_start, ld.l_len, ld.l_pid);
|
|
}
|
|
}
|
|
|
|
/* The following code is basically ripped out of fcntl() */
|
|
|
|
/*
|
|
* *** NOTE ***
|
|
* The SVID does not say what to return on file access errors!
|
|
* Here, EBADF is returned, which is compatible with S5R3
|
|
* and is less confusing than EACCES
|
|
*/
|
|
/* check access permissions */
|
|
if (cmd != F_GETLK) {
|
|
switch (ld.l_type) {
|
|
case F_RDLCK:
|
|
if (!(flag & FREAD)) {
|
|
error = EBADF;
|
|
goto out;
|
|
}
|
|
break;
|
|
case F_WRLCK:
|
|
if (!(flag & FWRITE)) {
|
|
error = EBADF;
|
|
goto out;
|
|
}
|
|
break;
|
|
case F_UNLCK:
|
|
break;
|
|
default:
|
|
error = EINVAL;
|
|
goto out;
|
|
}
|
|
}
|
|
|
|
/* convert negative lengths to positive */
|
|
if (ld.l_len < 0) {
|
|
ld.l_start += ld.l_len; /* adjust start point */
|
|
ld.l_len = -(ld.l_len); /* absolute value */
|
|
}
|
|
|
|
/* check for validity */
|
|
if (ld.l_start < 0) {
|
|
error = EINVAL;
|
|
goto out;
|
|
}
|
|
/*
|
|
* Dispatch out to vnode layer to do the actual locking.
|
|
* Then, translate error codes for SVID compatibility
|
|
*/
|
|
error = VOP_LOCKCTL(vp, &ld, cmd, u.u_cred,
|
|
RSL_PID(sp->s_mntindx, sp->s_epid));
|
|
if (error) {
|
|
if (error == EWOULDBLOCK)
|
|
error = EACCES;
|
|
goto out;
|
|
}
|
|
/*
|
|
* If request was to set a lock, allocate a server locking record.
|
|
* These are attached to the receive descriptor for the file.
|
|
* They are used to release locks when the client does a close or
|
|
* the connection is broken. They are also freed at that time.
|
|
*/
|
|
if (((cmd == F_SETLK) || (cmd == F_SETLKW)) && (ld.l_type != F_UNLCK))
|
|
rsl_alloc(sp->s_rdp, sp->s_epid, (long)sp->s_mntindx, u.u_cred);
|
|
|
|
/* If data is to go out, send it out (DUCOPYOUT) (old 5.3.0 style) */
|
|
if (cmd == F_GETLK && !frcache) {
|
|
data_bp = salocbuf(sizeof (struct response), BPRI_MED);
|
|
msg_out = (struct response *)PTOMSG(data_bp->b_rptr);
|
|
msg_out->rp_type = RESP_MSG;
|
|
msg_out->rp_opcode = DUCOPYOUT;
|
|
msg_out->rp_bufptr = arg;
|
|
msg_out->rp_bp = (long) data_bp;
|
|
msg_out->rp_subyte = 0; /* Message contains data */
|
|
msg_out->rp_count = size;
|
|
msgsz = sizeof (struct response) - DATASIZE + size;
|
|
msg_out->rp_copysync = 0;
|
|
msg_out->rp_errno = 0;
|
|
/* Convert from local to RFS flock structure */
|
|
((struct rfs_flock *) &ld)->l_pid = ld.l_pid;
|
|
bcopy((caddr_t) &ld, (caddr_t) msg_out->rp_data, (u_int) size);
|
|
error = sndmsg(sp->s_sdp, data_bp, msgsz, (rcvd_t) NULL);
|
|
DUPRINT6(DB_SERVE, "rs_fcntl: DUCOPYOUT: type %x, whence %x, start %x, len %x, pid %x\n", ld.l_type, ld.l_whence, ld.l_start, ld.l_len, ld.l_pid);
|
|
}
|
|
out:
|
|
chkrsig(sp, &error);
|
|
|
|
/* Make response message */
|
|
make_response(sp, (mblk_t **) NULL, error, (struct vnode *) NULL,
|
|
(struct vattr *) NULL, out_bp, outsize);
|
|
msg_out = (struct response *)PTOMSG((*out_bp)->b_rptr);
|
|
|
|
/* New style (5.3.1) -- return lock with response */
|
|
if (cmd == F_GETLK && frcache) {
|
|
msg_out->rp_bufptr = arg;
|
|
*outsize = sizeof (struct response) - DATASIZE + size;
|
|
/* Convert from local to RFS flock structure */
|
|
((struct rfs_flock *) &ld)->l_pid = ld.l_pid;
|
|
((struct rfs_flock *) &ld)->l_whence = ld.l_whence;
|
|
((struct rfs_flock *) &ld)->l_start = ld.l_start;
|
|
((struct rfs_flock *) &ld)->l_len = ld.l_len;
|
|
((struct rfs_flock *) &ld)->l_type = ld.l_type;
|
|
bcopy((caddr_t) &ld, (caddr_t) msg_out->rp_data, (u_int) size);
|
|
}
|
|
msg_out->rp_rval = FCNTLTORFS(cmd);
|
|
|
|
DUPRINT3(DB_SERVE, "rs_fcntl: result %d, vp %x\n", error, vp);
|
|
(void) splx(s);
|
|
return (error);
|
|
}
|
|
|
|
/*ARGSUSED*/
|
|
rs_rmdir(sp, in_bp, out_bp, outsize, gift)
|
|
struct serv_proc *sp;
|
|
mblk_t *in_bp, **out_bp;
|
|
int *outsize;
|
|
rcvd_t *gift;
|
|
{
|
|
register struct request *msg_in;
|
|
register char *name;
|
|
struct vnode *vp = (struct vnode *) NULL;
|
|
struct vnode *dvp = (struct vnode *) NULL;
|
|
int error = 0;
|
|
|
|
msg_in = (struct request *) PTOMSG(in_bp->b_rptr);
|
|
DUPRINT4(DB_SERVE, "rs_rmdir: sp %x, name %s, rd->vp %x\n",
|
|
sp, msg_in->rq_data, sp->s_rdp->rd_vnode);
|
|
|
|
/* Get dir name from request message */
|
|
name = msg_in->rq_data;
|
|
|
|
/* Set the current working and root directories */
|
|
set_dir(sp->s_rdp, msg_in->rq_rrdir);
|
|
|
|
/* Get vnode for file to be rmdir'ed */
|
|
error = rs_lookupname(name, UIOSEG_KERNEL, NO_FOLLOW, sp, &dvp, &vp);
|
|
if (error)
|
|
goto out;
|
|
|
|
/* make sure there is an entry */
|
|
if (vp == (struct vnode *)0) {
|
|
error = ENOENT;
|
|
goto out;
|
|
}
|
|
/* make sure filesystem is writeable */
|
|
if (vp->v_vfsp->vfs_flag & VFS_RDONLY) {
|
|
error = EROFS;
|
|
goto out;
|
|
}
|
|
/* don't unlink the root of a mounted filesystem. */
|
|
if (vp->v_flag & VROOT) {
|
|
error = EBUSY;
|
|
goto out;
|
|
}
|
|
/* Must be a directory */
|
|
if (vp->v_type != VDIR) {
|
|
error = ENOTDIR;
|
|
goto out;
|
|
}
|
|
|
|
/* release vnode before removing */
|
|
VN_RELE(vp);
|
|
vp = (struct vnode *)0;
|
|
|
|
/* remove the directory */
|
|
error = VOP_RMDIR(dvp, name, u.u_cred);
|
|
|
|
out:
|
|
/* Make response message */
|
|
make_response(sp, &in_bp, error, (struct vnode *) NULL,
|
|
(struct vattr *) NULL, out_bp, outsize);
|
|
|
|
/* Free the request buffer (and the vnode if error) */
|
|
if (in_bp)
|
|
freemsg(in_bp);
|
|
if (vp)
|
|
VN_RELE(vp);
|
|
if (dvp)
|
|
VN_RELE(dvp);
|
|
|
|
DUPRINT4(DB_SERVE, "rs_rmdir: result %d, name %s, vp %x\n",
|
|
error, name, vp);
|
|
return (error);
|
|
}
|
|
|
|
/*ARGSUSED*/
|
|
rs_mkdir(sp, in_bp, out_bp, outsize, gift)
|
|
struct serv_proc *sp;
|
|
mblk_t *in_bp, **out_bp;
|
|
int *outsize;
|
|
rcvd_t *gift;
|
|
{
|
|
register struct request *msg_in;
|
|
register char *name;
|
|
struct vnode *dvp = (struct vnode *) NULL;
|
|
struct vnode *vp = (struct vnode *) NULL;
|
|
struct vattr va;
|
|
int error = 0;
|
|
|
|
msg_in = (struct request *) PTOMSG(in_bp->b_rptr);
|
|
DUPRINT5(DB_SERVE, "rs_mkdir: sp %x, name %s, mode %x, rd->vp %x\n",
|
|
sp, msg_in->rq_data, msg_in->rq_fmode, sp->s_rdp->rd_vnode);
|
|
|
|
/* Get file name and mode change from request message */
|
|
name = msg_in->rq_data;
|
|
vattr_null(&va);
|
|
va.va_mode = (msg_in->rq_fmode & 07777) & ~msg_in->rq_cmask;
|
|
va.va_type = VDIR;
|
|
|
|
/* Set the current working and root directories */
|
|
set_dir(sp->s_rdp, msg_in->rq_rrdir);
|
|
|
|
/* Get vnode for directory of file to be mkdir'ed */
|
|
if (error = rs_lookupname(name, UIOSEG_KERNEL, NO_FOLLOW, sp,
|
|
&dvp, (struct vnode **) NULL))
|
|
goto out;
|
|
|
|
/* Can't change mode on read-only filesystems */
|
|
if (dvp->v_vfsp->vfs_flag & VFS_RDONLY) {
|
|
error = EROFS;
|
|
goto out;
|
|
}
|
|
/* Make the directory */
|
|
error = VOP_MKDIR(dvp, name, &va, &vp, u.u_cred);
|
|
out:
|
|
/* Make response message */
|
|
make_response(sp, &in_bp, error, (struct vnode *) NULL,
|
|
(struct vattr *) NULL, out_bp, outsize);
|
|
|
|
/* Free the request buffer (and the vnode if error) */
|
|
if (in_bp)
|
|
freemsg(in_bp);
|
|
if (vp)
|
|
VN_RELE(vp);
|
|
if (dvp)
|
|
VN_RELE(dvp);
|
|
|
|
DUPRINT4(DB_SERVE, "rs_mkdir: result %d, name %s, vp %x\n",
|
|
error, name, vp);
|
|
return (error);
|
|
}
|
|
|
|
/*
|
|
* Server side of RFS remote mount
|
|
*/
|
|
rs_srmount(sp, in_bp, out_bp, outsize, gift)
|
|
struct serv_proc *sp;
|
|
mblk_t *in_bp, **out_bp;
|
|
int *outsize;
|
|
rcvd_t *gift;
|
|
{
|
|
extern struct advertise *findadv();
|
|
extern struct timeval time;
|
|
register struct request *msg_in;
|
|
register struct response *msg_out;
|
|
struct srmnt *smp = (struct srmnt *) NULL;
|
|
struct advertise *ap;
|
|
register struct vnode *vp;
|
|
char resname[NMSZ];
|
|
int cl_mntindx;
|
|
struct vattr vattr;
|
|
long rwflag;
|
|
int error = 0;
|
|
|
|
DUPRINT3(DB_SERVE, "rs_srmount: sp %x, rd->vp %x\n",
|
|
sp, sp->s_rdp->rd_vnode);
|
|
msg_in = (struct request *) PTOMSG(in_bp->b_rptr);
|
|
rwflag = msg_in->rq_flag;
|
|
|
|
/* For first mount on circuit initialize circuit sysid and time */
|
|
if (sp->s_gdpp->mntcnt == 0) {
|
|
hibyte(sp->s_gdpp->sysid) = lobyte(loword(msg_in->rq_sysid));
|
|
sp->s_gdpp->time = msg_in->rq_synctime - time.tv_sec;
|
|
}
|
|
|
|
/* De-serialize the resource name */
|
|
(void) fcanon(rfs_string, msg_in->rq_data, resname);
|
|
|
|
/* Free the request buffer */
|
|
freemsg(in_bp);
|
|
|
|
/* Find the resource in the table of advertised resources */
|
|
if ((ap = findadv(resname)) == (struct advertise *) NULL) {
|
|
error = ENODEV;
|
|
goto out;
|
|
}
|
|
/* Get the root vnode of the resource */
|
|
vp = ap->a_queue->rd_vnode;
|
|
|
|
/* Deny a read/write mount request on a read-only resource */
|
|
if ((ap->a_flags & A_RDONLY) && !(rwflag & RFS_RDONLY)) {
|
|
error = EROFS;
|
|
goto out;
|
|
}
|
|
ap->a_count++;
|
|
|
|
/* see if client is authorized */
|
|
if (ap->a_clist && !checkalist(ap->a_clist, sp->s_gdpp->token.t_uname)) {
|
|
error = EACCES;
|
|
goto out;
|
|
}
|
|
/* Give up if resource has been unadvertised */
|
|
if (ap->a_flags & A_MINTER) {
|
|
error = ENONET;
|
|
goto out;
|
|
}
|
|
/* allocate an entry in the srmount table, and fill it in */
|
|
if (error = alocsrm(vp, sp->s_gdpp->sysid, &smp))
|
|
goto out;
|
|
|
|
cl_mntindx = sp->s_mntindx; /* Get client mount index */
|
|
sp->s_mntindx = smp - srmount; /* Store server mount index */
|
|
|
|
/* Create rd_user struct for root of mount point, for recovery */
|
|
if (cr_rduser(ap->a_queue, sp) == (struct rd_user *) NULL) {
|
|
error = ENOSPC;
|
|
goto out;
|
|
}
|
|
|
|
smp->sr_sysid = sp->s_gdpp->sysid;
|
|
smp->sr_rootvnode = vp;
|
|
smp->sr_mntindx = cl_mntindx;
|
|
smp->sr_flags = MINUSE;
|
|
smp->sr_bcount = 0;
|
|
smp->sr_slpcnt = 0;
|
|
if (rwflag & RFS_RDONLY)
|
|
smp->sr_flags |= MRDONLY;
|
|
smp->sr_refcnt = 1;
|
|
VN_HOLD(vp);
|
|
*gift = ap->a_queue;
|
|
sp->s_gdpp->mntcnt++;
|
|
(*gift)->rd_refcnt++;
|
|
|
|
/* Get mount point vnode attributes for response. */
|
|
error = VOP_GETATTR(vp, &vattr, u.u_cred);
|
|
out:
|
|
/* Make response message */
|
|
make_response(sp, (mblk_t **) NULL, error, vp, &vattr, out_bp, outsize);
|
|
|
|
msg_out = (struct response *)PTOMSG((*out_bp)->b_rptr);
|
|
msg_out->rp_mntindx = smp - srmount;
|
|
|
|
if (error) {
|
|
/*
|
|
* If last user of resource and it has been unadvertised,
|
|
* free the advertise table entry and associated vnode
|
|
*/
|
|
if (ap && (--(ap->a_count) == 0) && (ap->a_flags & A_MINTER)) {
|
|
ap->a_flags = A_FREE;
|
|
VN_RELE(ap->a_queue->rd_vnode);
|
|
}
|
|
}
|
|
DUPRINT3(DB_SERVE, "rs_srmount: result %d, vp %x\n", error, vp);
|
|
return (error);
|
|
}
|
|
|
|
|
|
/*
|
|
* Server side of RFS remote unmount
|
|
*/
|
|
/*ARGSUSED*/
|
|
rs_srumount(sp, in_bp, out_bp, outsize, gift)
|
|
struct serv_proc *sp;
|
|
mblk_t *in_bp, **out_bp;
|
|
int *outsize;
|
|
rcvd_t *gift;
|
|
{
|
|
register struct request *msg_in;
|
|
struct srmnt *smp = (struct srmnt *) NULL;
|
|
int mntindx;
|
|
extern int nsrmount;
|
|
extern struct advertise *getadv();
|
|
struct vnode *vp;
|
|
int error = 0;
|
|
|
|
msg_in = (struct request *) PTOMSG(in_bp->b_rptr);
|
|
mntindx = msg_in->rq_mntindx;
|
|
DUPRINT3(DB_SERVE, "rs_srumount: sp %x, mntindx %d\n", sp, mntindx);
|
|
|
|
if (mntindx < 0 || mntindx >= nsrmount) {
|
|
error = EINVAL;
|
|
goto out;
|
|
}
|
|
/* Get server side mnt table entry and associated vnode for mnt point */
|
|
smp = &srmount[mntindx];
|
|
vp = smp->sr_rootvnode;
|
|
|
|
/* Release mount table entry and associated resources */
|
|
if (error = srumount(smp, vp))
|
|
goto out;
|
|
|
|
/* Release receive descriptor, associated circuit and vnode */
|
|
del_rcvd(sp->s_rdp, sp);
|
|
sp->s_gdpp->mntcnt--;
|
|
VN_RELE(vp);
|
|
out:
|
|
/* Make response message */
|
|
make_response(sp, &in_bp, error, (struct vnode *) NULL,
|
|
(struct vattr *) NULL, out_bp, outsize);
|
|
|
|
/* Free the request buffer */
|
|
if (in_bp)
|
|
freemsg(in_bp);
|
|
|
|
DUPRINT3(DB_SERVE, "rs_srumount: result %d, vp %x\n", error, vp);
|
|
return (error);
|
|
}
|
|
|
|
/*
|
|
* DCHUNK is the maximum number of bytes of directory entries the server
|
|
* will return to the client, regardless of what is asked for. The value
|
|
* is chosen so that after XDR expansion it will still be comfortably less
|
|
* than the maximum RFS message size (DATASIZE bytes). We can't currently
|
|
* send more because of RFS heterogeneity bugs.
|
|
*/
|
|
#define DCHUNK 512
|
|
|
|
/*ARGSUSED*/
|
|
rs_getdents(sp, in_bp, out_bp, outsize, gift)
|
|
struct serv_proc *sp;
|
|
mblk_t *in_bp, **out_bp;
|
|
int *outsize;
|
|
rcvd_t *gift;
|
|
{
|
|
register struct request *msg_in;
|
|
register struct response *msg_out;
|
|
struct vnode *vp = (struct vnode *) NULL;
|
|
long base, count, offset;
|
|
int reqsize, chunksize;
|
|
int error = 0;
|
|
struct uio uio;
|
|
struct iovec iov;
|
|
caddr_t buf = (caddr_t) NULL;
|
|
caddr_t bufp;
|
|
int bytes_read;
|
|
struct dirent *idp;
|
|
struct rfs_dirent *odp;
|
|
|
|
msg_in = (struct request *) PTOMSG(in_bp->b_rptr);
|
|
DUPRINT6(DB_SERVE, "rs_getdents: sp %x, offset %d, count %d, base %x, rd->vp %x\n", sp, msg_in->rq_offset, msg_in->rq_count, msg_in->rq_base, sp->s_rdp->rd_vnode);
|
|
|
|
/*
|
|
* Get syscall params: base, count, offset and mode are implicit
|
|
* params supplied from client's file table entry
|
|
*/
|
|
base = msg_in->rq_base;
|
|
offset = msg_in->rq_offset;
|
|
reqsize = msg_in->rq_count;
|
|
chunksize = reqsize > DCHUNK ? DCHUNK : reqsize;
|
|
freemsg(in_bp);
|
|
/* Get the vnode for the file */
|
|
vp = sp->s_rdp->rd_vnode;
|
|
|
|
/* Initialize uio for data copy to temp buffer */
|
|
buf = (caddr_t)new_kmem_alloc((u_int)chunksize, KMEM_SLEEP);
|
|
uio.uio_iov = &iov;
|
|
uio.uio_iovcnt = 1;
|
|
uio.uio_seg = UIOSEG_KERNEL;
|
|
uio.uio_offset = offset;
|
|
uio.uio_resid = chunksize;
|
|
iov.iov_len = chunksize;
|
|
iov.iov_base = bufp = buf;
|
|
|
|
/* Read data into buffer */
|
|
error = VOP_READDIR(vp, &uio, u.u_cred);
|
|
bytes_read = chunksize - uio.uio_resid;
|
|
|
|
/* Get response message */
|
|
make_response(sp, (mblk_t **) NULL, error, (struct vnode *) NULL,
|
|
(struct vattr *) NULL, out_bp, outsize);
|
|
|
|
/*
|
|
* Copy the directory entries into the response buffer, converting
|
|
* to RFS format
|
|
*/
|
|
msg_out = (struct response *) PTOMSG((*out_bp)->b_rptr);
|
|
if (!error) {
|
|
for (count=0,
|
|
idp = (struct dirent *) bufp,
|
|
odp = (struct rfs_dirent *) msg_out->rp_data;
|
|
count < bytes_read;
|
|
count += idp->d_reclen,
|
|
idp = (struct dirent *) ((char *) idp + idp->d_reclen),
|
|
odp = (struct rfs_dirent *)((char *)odp + odp->d_reclen)) {
|
|
odp->d_ino = idp->d_fileno;
|
|
odp->d_off = idp->d_off;
|
|
odp->d_reclen =
|
|
(((unsigned) odp->d_name - (unsigned) odp) +
|
|
idp->d_namlen + 1 + 3) & ~3;
|
|
idp->d_name[idp->d_namlen] = '\0';
|
|
(void) strcpy(odp->d_name, idp->d_name);
|
|
DUPRINT4(DB_SERVE, " ino %d, reclen %d, name %s\n",
|
|
odp->d_ino, odp->d_reclen, odp->d_name);
|
|
}
|
|
msg_out->rp_subyte = 0; /* Message contains data */
|
|
msg_out->rp_count =
|
|
(long) ((unsigned) odp - (unsigned) msg_out->rp_data);
|
|
msg_out->rp_rval = msg_out->rp_count;
|
|
msg_out->rp_offset = uio.uio_offset;
|
|
msg_out->rp_bufptr = base;
|
|
*outsize = sizeof (struct response) - DATASIZE +
|
|
msg_out->rp_count;
|
|
}
|
|
DUPRINT6(DB_SERVE, "rs_readdir: rslt %d, cnt %d, addr %x, rval %d, su %d\n",
|
|
error, msg_out->rp_count, (unsigned) msg_out->rp_bufptr,
|
|
msg_out->rp_rval, msg_out->rp_subyte);
|
|
kmem_free((caddr_t)buf, (u_int)chunksize);
|
|
return (error);
|
|
}
|
|
|
|
/*ARGSUSED*/
|
|
rs_read(sp, in_bp, out_bp, outsize, gift)
|
|
struct serv_proc *sp;
|
|
mblk_t *in_bp, **out_bp;
|
|
int *outsize;
|
|
rcvd_t *gift;
|
|
{
|
|
register struct request *msg_in;
|
|
register struct response *msg_out;
|
|
struct vnode *vp = (struct vnode *) NULL;
|
|
long mode, base, count, offset;
|
|
int reqsize;
|
|
int ioflag;
|
|
int error = 0;
|
|
struct uio uio;
|
|
struct iovec iov;
|
|
mblk_t *dbp = (mblk_t *) NULL;
|
|
mblk_t *ack_bp = (mblk_t *) NULL;
|
|
rcvd_t ackrd = (rcvd_t) NULL;
|
|
struct vattr va;
|
|
int msgsz;
|
|
int no_sig = 1;
|
|
int rs;
|
|
int mand_chg = 0;
|
|
int size;
|
|
int raw_read = 0; /* Size of i/o requests for a raw device */
|
|
int raw_off; /* Off into current raw read for this RFS resp. msg */
|
|
int raw_ret; /* raw dev: #bytes of data ret'd in this RFS resp. msg */
|
|
|
|
msg_in = (struct request *) PTOMSG(in_bp->b_rptr);
|
|
DUPRINT6(DB_SERVE, "rs_read: sp %x, offset %d, count %d, mode %x, rd->vp %x\n", sp, msg_in->rq_offset, msg_in->rq_count, msg_in->rq_fmode, sp->s_rdp->rd_vnode);
|
|
|
|
/*
|
|
* Get syscall params: base, count, offset and mode are implicit
|
|
* params supplied from client's file table entry
|
|
*/
|
|
base = msg_in->rq_base;
|
|
offset = msg_in->rq_offset;
|
|
reqsize = msg_in->rq_count;
|
|
mode = msg_in->rq_fmode;
|
|
ioflag = (mode & RFS_FAPPEND ? IO_APPEND : 0) |
|
|
(mode & RFS_FSYNC ? IO_SYNC : 0);
|
|
mode = RFSTOFFLAG(msg_in->rq_fmode);
|
|
/* Get the vnode for the file */
|
|
vp = sp->s_rdp->rd_vnode;
|
|
|
|
/* Set client remote signal, if any */
|
|
if (sp->s_op == DUREAD)
|
|
setrsig(sp, in_bp);
|
|
|
|
/* If file has changed to mand. lockable, inform client via NACK */
|
|
if (!(msg_in->rq_flags & RQ_MNDLCK) &&
|
|
(((struct message *)in_bp->b_rptr)->m_stat & VER1) &&
|
|
mnd_lck(vp, u.u_cred)) {
|
|
error = ENOMEM;
|
|
mand_chg = 1;
|
|
freemsg(in_bp);
|
|
goto out;
|
|
}
|
|
freemsg(in_bp);
|
|
|
|
/* Recover if system call is interrupted */
|
|
if (setjmp(&u.u_qsave)) {
|
|
error = EINTR;
|
|
goto out;
|
|
}
|
|
/* Initialize uio for data copy from system buffer to response message */
|
|
uio.uio_iov = &iov;
|
|
uio.uio_iovcnt = 1;
|
|
uio.uio_seg = UIOSEG_KERNEL;
|
|
uio.uio_offset = offset;
|
|
uio.uio_fmode = mode;
|
|
|
|
/*
|
|
* If necessary, setup for raw i/o. Allocate a user address space
|
|
* (if one isn't already there) so that the resulting physio()
|
|
* requests will work; data will be read into the user address space
|
|
* (physio() won't work to kernel address space) and copied back in.
|
|
* Also, choose the size in which reads will be done. Requests
|
|
* are handed to the device (via VOP_RDWR) with the size the client
|
|
* specified (unless they exceed the size of the segment allocated
|
|
* in the user's address space (segsize)). This is to preserve things
|
|
* such as tape block sizes.
|
|
*/
|
|
if (vp->v_type == VCHR) {
|
|
if (sp->s_proc->p_as == NULL) {
|
|
if ((sp->s_proc->p_as = rs_getas(segsize)) == NULL) {
|
|
error = ENOMEM;
|
|
goto out;
|
|
}
|
|
}
|
|
raw_read = (reqsize <= segsize ? reqsize : DATASIZE);
|
|
raw_off = raw_read + 1;
|
|
}
|
|
|
|
/* Read and send resp. back in DATASIZE chunks, as RFS requires */
|
|
for (count = reqsize; ; count -= DATASIZE, base += DATASIZE) {
|
|
/* Setup response message and copy params */
|
|
dbp = salocbuf(sizeof (struct response), BPRI_MED);
|
|
size = (count > DATASIZE ? DATASIZE : count);
|
|
msg_out = (struct response *)PTOMSG(dbp->b_rptr);
|
|
msg_out->rp_type = RESP_MSG;
|
|
msg_out->rp_opcode = DUCOPYOUT;
|
|
msg_out->rp_bufptr = base;
|
|
msg_out->rp_bp = (long) dbp;
|
|
msg_out->rp_subyte = 0; /* Message contains data */
|
|
msg_out->rp_count = size;
|
|
msg_out->rp_errno = 0;
|
|
msgsz = sizeof (struct response) - DATASIZE + size;
|
|
uio.uio_resid = size;
|
|
if (vp->v_type == VFIFO) /* FIFOs always expect 0 offset */
|
|
uio.uio_offset = 0;
|
|
iov.iov_len = size;
|
|
iov.iov_base = msg_out->rp_data;
|
|
|
|
/* Normal read, put next DATASIZE chunk in response message */
|
|
if (!raw_read) {
|
|
error = VOP_RDWR(vp, &uio, UIO_READ, ioflag, u.u_cred);
|
|
} else { /* raw dev */
|
|
/* If need next raw-size block, read it to user land */
|
|
if (raw_off >= raw_read) {
|
|
raw_off = 0;
|
|
raw_read = MIN(count, raw_read);
|
|
uio.uio_seg = UIOSEG_USER;
|
|
uio.uio_iov = &iov;
|
|
uio.uio_iovcnt = 1;
|
|
uio.uio_offset = 0;
|
|
iov.iov_base = SEGSTART;
|
|
iov.iov_len = raw_read;
|
|
uio.uio_resid = raw_read;
|
|
error =
|
|
VOP_RDWR(vp, &uio, UIO_READ, ioflag, u.u_cred);
|
|
if (error)
|
|
goto out;
|
|
raw_read -= uio.uio_resid;
|
|
}
|
|
/* copyin chunk from userland for next response msg */
|
|
raw_ret = MIN(size, raw_read - raw_off);
|
|
error =
|
|
copyin(SEGSTART + raw_off, msg_out->rp_data,
|
|
(u_int) raw_ret);
|
|
if (error)
|
|
goto out;
|
|
raw_off += raw_ret;
|
|
uio.uio_resid = size - raw_ret;
|
|
}
|
|
|
|
DUPRINT6(DB_SERVE, "rs_read: req %d, rd %d, count %d, ccnt %d, caddr %x\n", size, size - uio.uio_resid, count, sp->s_sdp->sd_copycnt,
|
|
(unsigned) msg_out->rp_bufptr);
|
|
|
|
srmount[sp->s_mntindx].sr_bcount +=
|
|
(size - uio.uio_resid + RFS_BKSIZE/2) / RFS_BKSIZE;
|
|
|
|
if (error || uio.uio_resid || count <= DATASIZE)
|
|
goto out;
|
|
|
|
/* Send back the data */
|
|
sp->s_sdp->sd_copycnt++;
|
|
if (sp->s_sdp->sd_copycnt < FILE_QSIZE) {
|
|
msg_out->rp_copysync = 0;
|
|
error = sndmsg(sp->s_sdp, dbp, msgsz, (rcvd_t) NULL);
|
|
dbp = (mblk_t *) NULL;
|
|
if (error)
|
|
goto out;
|
|
} else { /* Flow control: let client ACK before sending more */
|
|
sp->s_sdp->sd_copycnt = 0;
|
|
msg_out->rp_copysync = 1; /* Signals client to ACK */
|
|
/* Get rd to receive client ACK on */
|
|
if (!ackrd && !(ackrd = cr_rcvd(FILE_QSIZE, SPECIFIC))) {
|
|
error = ENOMEM;
|
|
goto out;
|
|
}
|
|
ackrd->rd_sd = sp->s_sdp;
|
|
error = sndmsg(sp->s_sdp, dbp, msgsz, ackrd);
|
|
dbp = (mblk_t *) NULL;
|
|
if (error)
|
|
goto out;
|
|
/* Wait for the ACK */
|
|
if (error = de_queue(ackrd, &ack_bp, (sndd_t) NULL, &rs,
|
|
&no_sig, (sndd_t) NULL))
|
|
goto out;
|
|
DUPRINT3(DB_SERVE, "rs_read: ack, opcode %d, ccnt %d\n",
|
|
((struct response *)PTOMSG(ack_bp->b_rptr))->rp_opcode,
|
|
sp->s_sdp->sd_copycnt);
|
|
freemsg(ack_bp);
|
|
}
|
|
}
|
|
out:
|
|
chkrsig(sp, &error);
|
|
|
|
/* Return the file size */
|
|
if (!error)
|
|
error = VOP_GETATTR(vp, &va, u.u_cred);
|
|
|
|
/* Last chunk is returned as response message */
|
|
if (dbp)
|
|
*out_bp = dbp;
|
|
else
|
|
make_response(sp, (mblk_t **) NULL, error, (struct vnode *) NULL,
|
|
(struct vattr *) NULL, out_bp, outsize);
|
|
|
|
msg_out = (struct response *) PTOMSG((*out_bp)->b_rptr);
|
|
msg_out->rp_opcode = sp->s_op;
|
|
msg_out->rp_sig = SIGTORFS(GET_SIGS(sp->s_proc));
|
|
msg_out->rp_sysid = sp->s_sysid;
|
|
msg_out->rp_errno = ERRTORFS(error);
|
|
msg_out->rp_rval = count - size + uio.uio_resid;
|
|
|
|
if (mand_chg) {
|
|
msg_out->rp_type = NACK_MSG;
|
|
msg_out->rp_cache |= RP_MNDLCK;
|
|
}
|
|
if (error) {
|
|
msg_out->rp_subyte = 1;
|
|
msg_out->rp_count = 0;
|
|
*outsize = sizeof (struct response) - DATASIZE;
|
|
} else {
|
|
msg_out->rp_isize = va.va_size;
|
|
msg_out->rp_count = size - uio.uio_resid;
|
|
msg_out->rp_subyte = size - uio.uio_resid ? 0 : 1;
|
|
*outsize = sizeof (struct response) - DATASIZE +
|
|
msg_out->rp_count;
|
|
}
|
|
/* Cleanup */
|
|
sp->s_sdp->sd_copycnt = 0;
|
|
if (ackrd)
|
|
free_rcvd(ackrd);
|
|
|
|
DUPRINT6(DB_SERVE, "rs_read: rslt %d, cnt %d, addr %x, rval %d, su %d\n",
|
|
error, msg_out->rp_count, (unsigned) msg_out->rp_bufptr,
|
|
msg_out->rp_rval, msg_out->rp_subyte);
|
|
return (error);
|
|
}
|
|
|
|
|
|
/*ARGSUSED*/
|
|
rs_write(sp, in_bp, out_bp, outsize, gift)
|
|
struct serv_proc *sp;
|
|
mblk_t *in_bp, **out_bp;
|
|
int *outsize;
|
|
rcvd_t *gift;
|
|
{
|
|
register struct request *msg_in;
|
|
register struct response *msg_out;
|
|
register struct response *data_msg;
|
|
struct vnode *vp = (struct vnode *) NULL;
|
|
long mode, base, count, offset;
|
|
int reqsize;
|
|
int ioflag;
|
|
int error = 0;
|
|
struct uio uio;
|
|
struct iovec iov;
|
|
mblk_t *data_bp = (mblk_t *) NULL;
|
|
mblk_t *go_bp = (mblk_t *) NULL;
|
|
rcvd_t rd = (rcvd_t) NULL;
|
|
struct vattr va;
|
|
int size, msgsz;
|
|
int no_sig = 1;
|
|
int rs;
|
|
int mand_chg = 0;
|
|
int raw_write = 0; /* Size of i/o requests for a raw device */
|
|
int raw_off; /* Off into currently accumulating raw write */
|
|
|
|
|
|
msg_in = (struct request *) PTOMSG(in_bp->b_rptr);
|
|
DUPRINT6(DB_SERVE, "rs_write: sp %x, offset %d, count %d, mode %x, rd->vp %x\n", sp, msg_in->rq_offset, msg_in->rq_count, msg_in->rq_fmode, sp->s_rdp->rd_vnode);
|
|
|
|
/*
|
|
* Get syscall params: base, count, offset and mode are implicit
|
|
* params supplied from client's file table entry
|
|
*/
|
|
base = msg_in->rq_base;
|
|
offset = msg_in->rq_offset;
|
|
reqsize = msg_in->rq_count;
|
|
mode = msg_in->rq_fmode;
|
|
ioflag = (mode & RFS_FAPPEND ? IO_APPEND : 0) |
|
|
(mode & RFS_FSYNC ? IO_SYNC : 0);
|
|
mode = RFSTOFFLAG(msg_in->rq_fmode);
|
|
/* Get the vnode for the file */
|
|
vp = sp->s_rdp->rd_vnode;
|
|
|
|
/* Writing is not allowed to symbolic links */
|
|
if (vp->v_type == VLNK) {
|
|
error = EINVAL;
|
|
goto out;
|
|
}
|
|
/* ... or to read-only filesystems */
|
|
if (vp->v_vfsp->vfs_flag & VFS_RDONLY) {
|
|
error = EROFS;
|
|
goto out;
|
|
}
|
|
/* Set client remote signal, if any */
|
|
if (sp->s_op == DUWRITE)
|
|
setrsig(sp, in_bp);
|
|
|
|
/* If file has changed to mand. lockable, inform client via NACK */
|
|
if (!(msg_in->rq_flags & RQ_MNDLCK) &&
|
|
(((struct message *)in_bp->b_rptr)->m_stat & VER1) &&
|
|
mnd_lck(vp, u.u_cred)) {
|
|
error = ENOMEM;
|
|
mand_chg = 1;
|
|
freemsg(in_bp);
|
|
goto out;
|
|
}
|
|
/* Recover if system call is interrupted */
|
|
if (setjmp(&u.u_qsave)) {
|
|
error = EINTR;
|
|
goto out;
|
|
}
|
|
/* For append write, get end of file to append to. */
|
|
if (ioflag & IO_APPEND || (offset < 0 && sp->s_op == DUWRITEI)) {
|
|
if (error = VOP_GETATTR(vp, &va, u.u_cred))
|
|
goto out;
|
|
offset = va.va_size;
|
|
}
|
|
/* Create rd on which to receive rest of data */
|
|
if ((rd = cr_rcvd(FILE_QSIZE, SPECIFIC)) == (rcvd_t) NULL) {
|
|
error = ENOMEM;
|
|
goto out;
|
|
}
|
|
rd->rd_sd = sp->s_sdp;
|
|
rd->rd_qsize = SIGQSIZE;
|
|
|
|
/* Initialize uio for data copy from network to system buffers */
|
|
uio.uio_iov = &iov;
|
|
uio.uio_iovcnt = 1;
|
|
uio.uio_seg = UIOSEG_KERNEL;
|
|
uio.uio_offset = offset;
|
|
uio.uio_fmode = mode;
|
|
|
|
/*
|
|
* If necessary, setup for raw i/o. Allocate a user address space
|
|
* (if one isn't already there) for doing physio() to. Requests
|
|
* are handed to the device (via VOP_RDWR) with the size the client
|
|
* specified (unless they exceed the size of the segment allocated
|
|
* in the user's address space (segsize)). This is to preserve things
|
|
* such as tape block sizes.
|
|
*/
|
|
if (vp->v_type == VCHR) {
|
|
if (sp->s_proc->p_as == NULL) {
|
|
if ((sp->s_proc->p_as = rs_getas(segsize)) == NULL) {
|
|
error = ENOMEM;
|
|
goto out;
|
|
}
|
|
}
|
|
raw_write = (reqsize <= segsize ? reqsize : DATASIZE);
|
|
raw_off = 0;
|
|
}
|
|
|
|
/* Write data, send go-ahead and get more data, in DATASIZE chunks */
|
|
for (count = reqsize, data_bp = in_bp, size = msg_in->rq_prewrite,
|
|
iov.iov_base = msg_in->rq_data; ; ) {
|
|
/* Do the write */
|
|
uio.uio_resid = size;
|
|
iov.iov_len = size;
|
|
if (vp->v_type == VFIFO) /* FIFOs always expect 0 offset */
|
|
uio.uio_offset = 0;
|
|
|
|
/* Normal write: write the chunk received in this msg */
|
|
if (!raw_write) {
|
|
error = VOP_RDWR(vp, &uio, UIO_WRITE, ioflag, u.u_cred);
|
|
} else { /* raw write */
|
|
/* copyout this msg's data chunk to userland */
|
|
ASSERT(raw_off + size <= raw_write);
|
|
error =
|
|
copyout(iov.iov_base, SEGSTART + raw_off,
|
|
(u_int) size);
|
|
if (error) {
|
|
freemsg(data_bp);
|
|
data_bp = (mblk_t *) NULL;
|
|
goto out;
|
|
}
|
|
DUPRINT4(DB_SERVE, "rs_write: raw copyout %d, off %d, write size %d\n",
|
|
size, raw_off, raw_write);
|
|
raw_off += size;
|
|
uio.uio_resid = 0;
|
|
/* If got next raw-size block, write it */
|
|
if (raw_off >= raw_write) {
|
|
uio.uio_seg = UIOSEG_USER;
|
|
uio.uio_iov = &iov;
|
|
uio.uio_iovcnt = 1;
|
|
uio.uio_offset = 0;
|
|
iov.iov_base = SEGSTART;
|
|
iov.iov_len = raw_write;
|
|
uio.uio_resid = raw_write;
|
|
error =
|
|
VOP_RDWR(vp, &uio, UIO_WRITE, ioflag, u.u_cred);
|
|
DUPRINT4(DB_SERVE, "rs_write: raw write: raw_write %d, wrote %d, error %d\n",
|
|
raw_write, raw_write - uio.uio_resid, error);
|
|
raw_off = 0;
|
|
raw_write = MIN(count - size, raw_write);
|
|
}
|
|
}
|
|
|
|
freemsg(data_bp);
|
|
data_bp = (mblk_t *) NULL;
|
|
if (error)
|
|
goto out;
|
|
|
|
srmount[sp->s_mntindx].sr_bcount +=
|
|
(size - uio.uio_resid + RFS_BKSIZE/2) / RFS_BKSIZE;
|
|
|
|
if (uio.uio_resid) {
|
|
count -= (size - uio.uio_resid);
|
|
base += (size - uio.uio_resid);
|
|
goto out;
|
|
}
|
|
count -= size; base += size;
|
|
DUPRINT4(DB_SERVE, "rs_write: wrote %d, rem %d, newbase %x\n",
|
|
size, count, (unsigned) base);
|
|
if (count <= 0)
|
|
goto out;
|
|
|
|
/* Send back go-ahead message */
|
|
go_bp = salocbuf(sizeof (struct response), BPRI_MED);
|
|
size = (count > DATASIZE ? DATASIZE : count);
|
|
msg_out = (struct response *)PTOMSG(go_bp->b_rptr);
|
|
msg_out->rp_type = RESP_MSG;
|
|
msg_out->rp_opcode = DUCOPYIN;
|
|
msg_out->rp_bufptr = base;
|
|
msg_out->rp_bp = (long) go_bp;
|
|
msg_out->rp_count = size; /* Send back this much */
|
|
msg_out->rp_errno = 0;
|
|
msgsz = sizeof (struct response) - DATASIZE;
|
|
if (error = sndmsg(sp->s_sdp, go_bp, msgsz, rd))
|
|
goto out;
|
|
|
|
/* Get next chunk of data */
|
|
if (error = de_queue(rd, &data_bp, (sndd_t) NULL, &rs, &no_sig,
|
|
(sndd_t) NULL))
|
|
goto out;
|
|
data_msg = (struct response *)PTOMSG(data_bp->b_rptr);
|
|
if (data_msg->rp_errno) {
|
|
error = RFSTOERR(data_msg->rp_errno);
|
|
goto out;
|
|
}
|
|
ASSERT(data_msg->rp_count == size); /* Expect size we asked for */
|
|
iov.iov_base = data_msg->rp_data;
|
|
}
|
|
out:
|
|
chkrsig(sp, &error);
|
|
|
|
/* If synchronous specified, flush the write to disk */
|
|
if (ioflag & IO_SYNC && !error)
|
|
error = VOP_FSYNC(vp, u.u_cred);
|
|
|
|
/* Return the file size */
|
|
if (!error)
|
|
error = VOP_GETATTR(vp, &va, u.u_cred);
|
|
|
|
make_response(sp, (mblk_t **) NULL, error, (struct vnode *) NULL,
|
|
(struct vattr *) NULL, out_bp, outsize);
|
|
msg_out = (struct response *) PTOMSG((*out_bp)->b_rptr);
|
|
if (mand_chg) {
|
|
msg_out->rp_type = NACK_MSG;
|
|
msg_out->rp_cache |= RP_MNDLCK;
|
|
}
|
|
if (ioflag & IO_APPEND)
|
|
msg_out->rp_isize = offset;
|
|
else
|
|
msg_out->rp_isize = va.va_size;
|
|
msg_out->rp_rval = count;
|
|
|
|
if (rd)
|
|
free_rcvd(rd);
|
|
if (data_bp)
|
|
freemsg(data_bp);
|
|
|
|
DUPRINT3(DB_SERVE, "rs_write: rslt %d, rval %d\n",
|
|
error, msg_out->rp_rval);
|
|
return (error);
|
|
}
|
|
|
|
rs_coredump(sp, in_bp, out_bp, outsize, gift)
|
|
struct serv_proc *sp;
|
|
mblk_t *in_bp, **out_bp;
|
|
int *outsize;
|
|
rcvd_t *gift;
|
|
{
|
|
register struct request *msg_in;
|
|
char name[20];
|
|
struct vnode *vp = (struct vnode *) NULL;
|
|
int error = 0;
|
|
struct vattr vattr;
|
|
|
|
msg_in = (struct request *) PTOMSG(in_bp->b_rptr);
|
|
DUPRINT3(DB_SERVE, "rs_coredump: sp %x, rd->vp %x\n",
|
|
sp, sp->s_rdp->rd_vnode);
|
|
|
|
/* Set the current working and root directories */
|
|
set_dir(sp->s_rdp, msg_in->rq_rrdir);
|
|
|
|
/* Set attributes of the file */
|
|
vattr_null(&vattr);
|
|
vattr.va_type = VREG;
|
|
vattr.va_mode = 0666 & ~msg_in->rq_cmask;
|
|
(void) strcpy(name, "core");
|
|
|
|
/* Create the file */
|
|
error = rs_vncreate(name, UIOSEG_KERNEL, &vattr,
|
|
NONEXCL, VWRITE, sp, &vp);
|
|
if (error != 0)
|
|
goto out;
|
|
|
|
/* Zero the file */
|
|
vattr_null(&vattr);
|
|
vattr.va_size = 0;
|
|
if (error = VOP_SETATTR(vp, &vattr, u.u_cred))
|
|
goto out;
|
|
|
|
/* Get attributes of new vnode to return to client */
|
|
if (error = VOP_GETATTR(vp, &vattr, u.u_cred))
|
|
goto out;
|
|
|
|
if (vattr.va_nlink != 1) {
|
|
error = EFAULT;
|
|
goto out;
|
|
}
|
|
/* Make a receive descriptor for client requests on new vnode */
|
|
if (error = make_gift(vp, FILE_QSIZE, sp, gift))
|
|
goto out;
|
|
|
|
srmount[sp->s_mntindx].sr_refcnt++; /* New ref on this mnt point */
|
|
out:
|
|
/* Make response message */
|
|
make_response(sp, &in_bp, error, vp, &vattr, out_bp, outsize);
|
|
|
|
/* Free the request buffer (and the vnode if error) */
|
|
if (in_bp)
|
|
freemsg(in_bp);
|
|
if (error) {
|
|
if (vp)
|
|
VN_RELE(vp);
|
|
}
|
|
DUPRINT4(DB_SERVE, "rs_coredump: result %d, name %s, vp %x\n",
|
|
error, name, vp);
|
|
return (error);
|
|
}
|
|
|
|
/*ARGSUSED*/
|
|
rs_iput(sp, in_bp, out_bp, outsize, gift)
|
|
struct serv_proc *sp;
|
|
mblk_t *in_bp, **out_bp;
|
|
int *outsize;
|
|
rcvd_t *gift;
|
|
{
|
|
register struct request *msg_in;
|
|
struct srmnt *smp = (struct srmnt *) NULL;
|
|
int mntindx;
|
|
extern int nsrmount;
|
|
struct vnode *vp;
|
|
int error = 0;
|
|
|
|
msg_in = (struct request *) PTOMSG(in_bp->b_rptr);
|
|
mntindx = msg_in->rq_mntindx;
|
|
vp = sp->s_rdp->rd_vnode;
|
|
DUPRINT3(DB_SERVE, "rs_iput: sp %x, vnode %x\n", sp, vp);
|
|
|
|
if (mntindx < 0 || mntindx >= nsrmount) {
|
|
error = EINVAL;
|
|
goto out;
|
|
}
|
|
/* Release the vnode and associated resources */
|
|
smp = &srmount[mntindx];
|
|
--smp->sr_refcnt;
|
|
if (smp->sr_refcnt == 0) { /* Means erroneous client DUIPUT */
|
|
printf("serve DUIPUT: free srmount entry\n");
|
|
smp->sr_flags = MFREE;
|
|
}
|
|
del_rcvd(sp->s_rdp, sp);
|
|
VN_RELE(vp);
|
|
out:
|
|
/* Make response message */
|
|
make_response(sp, &in_bp, error, (struct vnode *) NULL,
|
|
(struct vattr *) NULL, out_bp, outsize);
|
|
|
|
/* Free the request buffer */
|
|
if (in_bp)
|
|
freemsg(in_bp);
|
|
|
|
DUPRINT2(DB_SERVE, "rs_iput: result %d\n", error);
|
|
return (error);
|
|
}
|
|
|
|
/*
|
|
* Update a remote inode with the current time. VOP_SETATTR accomplishes this.
|
|
* For 4.2 filesystem by calling iupdat(). For NFS by calling VOP_SETATTR() on
|
|
* server. However, in general VOP_SETATTR does not make a requirement that the
|
|
* attributes be flushed to stable storage as does FS_IUPDAT.
|
|
*/
|
|
/*ARGSUSED*/
|
|
rs_iupdate(sp, in_bp, out_bp, outsize, gift)
|
|
struct serv_proc *sp;
|
|
mblk_t *in_bp, **out_bp;
|
|
int *outsize;
|
|
rcvd_t *gift;
|
|
{
|
|
struct vnode *vp;
|
|
struct vattr va;
|
|
extern struct timeval time;
|
|
int error = 0;
|
|
|
|
freemsg(in_bp);
|
|
vp = sp->s_rdp->rd_vnode;
|
|
DUPRINT3(DB_SERVE, "rs_iupdate: sp %x, vnode %x\n", sp, vp);
|
|
|
|
/* Update the vnode with the current time */
|
|
vattr_null(&va);
|
|
va.va_atime = time;
|
|
va.va_mtime = time;
|
|
error = VOP_SETATTR(vp, &va, u.u_cred);
|
|
|
|
/* Make response message */
|
|
make_response(sp, (mblk_t **) NULL, error, (struct vnode *) NULL,
|
|
(struct vattr *) NULL, out_bp, outsize);
|
|
|
|
DUPRINT2(DB_SERVE, "rs_iupdate: result %d\n", error);
|
|
return (error);
|
|
}
|
|
|
|
/*
|
|
* Remote file system flush. Leave this a no-op for now since, 1) AT&T doesn't
|
|
* really do the appropriate thing either (they just flush the super-block),
|
|
* 2) if you had many clients mounting the same resource and each doing a
|
|
* sync() every 30 seconds, this would put a non-trivial load on the server.
|
|
* It's not clear that clients should be allowed to do remote sync's anyways.
|
|
* It's really a server responsibility.
|
|
*/
|
|
/*ARGSUSED*/
|
|
rs_uupdate(sp, in_bp, out_bp, outsize, gift)
|
|
struct serv_proc *sp;
|
|
mblk_t *in_bp, **out_bp;
|
|
int *outsize;
|
|
rcvd_t *gift;
|
|
{
|
|
struct vnode *vp = (struct vnode *) NULL;
|
|
int error = 0;
|
|
|
|
DUPRINT3(DB_SERVE, "rs_uupdate: sp %x, rd->vp %x\n", sp,
|
|
sp->s_rdp->rd_vnode);
|
|
|
|
freemsg(in_bp);
|
|
vp = sp->s_rdp->rd_vnode;
|
|
|
|
/* Make response message */
|
|
make_response(sp, (mblk_t **) NULL, error, (struct vnode *) NULL,
|
|
(struct vattr *) NULL, out_bp, outsize);
|
|
|
|
DUPRINT3(DB_SERVE, "rs_uupdate: result %d, vp %x\n",
|
|
error, vp);
|
|
return (error);
|
|
}
|
|
|
|
/*
|
|
* RFS syscalls come here which take a file pathname, but where the operation
|
|
* is only allowed on files local to the client. In this case the server has
|
|
* to evaluate the pathname because it may contain a ".." and eventually be
|
|
* resolved on the client. If the lookup returns with an EDOTDOT, then the
|
|
* remaining pathname is returned to the client; if it's successfully resolved
|
|
* on the server it's an EREMOTE error. Currently, the following syscalls use
|
|
* this:
|
|
* DUSYSACCT, DUADVERTISE, DUUNADVERTISE,
|
|
* DUMOUNT, DUUMOUNT, DURMOUNT, DURUMOUNT
|
|
*/
|
|
/*ARGSUSED*/
|
|
rs_clientop(sp, in_bp, out_bp, outsize, gift)
|
|
struct serv_proc *sp;
|
|
mblk_t *in_bp, **out_bp;
|
|
int *outsize;
|
|
rcvd_t *gift;
|
|
{
|
|
register struct request *msg_in;
|
|
register struct response *msg_out;
|
|
register char *name;
|
|
struct vnode *vp = (struct vnode *) NULL;
|
|
int error = 0;
|
|
|
|
msg_in = (struct request *) PTOMSG(in_bp->b_rptr);
|
|
DUPRINT4(DB_SERVE, "rs_clientop: sp %x, name %s, rd->vp %x\n",
|
|
sp, msg_in->rq_data, sp->s_rdp->rd_vnode);
|
|
|
|
/* Get file name and mode change from request message */
|
|
name = msg_in->rq_data;
|
|
|
|
/* Set the current working and root directories */
|
|
set_dir(sp->s_rdp, msg_in->rq_rrdir);
|
|
|
|
/* Lookup the file */
|
|
error = rs_lookupname(name, UIOSEG_KERNEL, NO_FOLLOW, sp,
|
|
(struct vnode **) NULL, &vp);
|
|
|
|
/* Make response message */
|
|
make_response(sp, &in_bp, error, (struct vnode *) NULL,
|
|
(struct vattr *) NULL, out_bp, outsize);
|
|
|
|
/* Free the request buffer, and the vnode */
|
|
if (in_bp)
|
|
freemsg(in_bp);
|
|
if (vp)
|
|
VN_RELE(vp);
|
|
|
|
/* Pathname was resolved on server: error */
|
|
if (!error) {
|
|
msg_out = (struct response *) PTOMSG((*out_bp)->b_rptr);
|
|
msg_out->rp_errno = RFS_EREMOTE;
|
|
error = EREMOTE;
|
|
}
|
|
|
|
DUPRINT4(DB_SERVE, "rs_clientop: result %d, name %s, vp %x\n",
|
|
error, name, vp);
|
|
return (error);
|
|
}
|
|
|
|
/*
|
|
* Handle client remote signal:
|
|
* If there's an active server handling the signalling client's request,
|
|
* signal that server.
|
|
* Else, look for a matching client request awaiting service and set the signal
|
|
* bit in the request. This will cause the server process who handles
|
|
* the request to signal itself.
|
|
*/
|
|
/*ARGSUSED*/
|
|
rs_rsignal(sp, in_bp, out_bp, outsize, gift)
|
|
struct serv_proc *sp;
|
|
mblk_t *in_bp, **out_bp;
|
|
int *outsize;
|
|
rcvd_t *gift;
|
|
{
|
|
register struct request *msg_in;
|
|
int cl_pid; /* Process id of signalling client */
|
|
int cl_sysid; /* Machine id of signalling client */
|
|
rcvd_t rdp; /* rd of signalling client's original request */
|
|
int s;
|
|
struct serv_proc *tp;
|
|
mblk_t *bp;
|
|
extern mblk_t *chkrdq();
|
|
struct message *msig;
|
|
|
|
msg_in = (struct request *) PTOMSG(in_bp->b_rptr);
|
|
DUPRINT5(DB_SERVE, "rs_rsignal: sp %x, cl sysid %x, srv sysid %x, epid %d, \n",
|
|
sp, msg_in->rq_sysid, sp->s_sysid, msg_in->rq_pid);
|
|
|
|
/* Get pid, sysid and rd of signalling client process from message */
|
|
cl_pid = msg_in->rq_pid;
|
|
cl_sysid = msg_in->rq_sysid;
|
|
rdp = inxtord(((struct message *)in_bp->b_rptr)->m_dest);
|
|
freemsg(in_bp);
|
|
|
|
/* Look for currently active server serving signalling client */
|
|
for (tp = s_active.sl_head;
|
|
tp != (struct serv_proc *) NULL; tp = tp->s_rlink) {
|
|
if (tp == sp)
|
|
continue;
|
|
if (tp->s_epid == cl_pid && tp->s_sysid == sp->s_sysid)
|
|
break;
|
|
}
|
|
|
|
/*
|
|
* If found, signal server; else set signal bit in matching client
|
|
* request awaiting service (if any)
|
|
*/
|
|
if (tp)
|
|
psignal(tp->s_proc, SIGTERM);
|
|
else {
|
|
s = splrf();
|
|
sp->s_sdp->sd_srvproc = (struct proc *) NULL;
|
|
if ((bp = chkrdq(rdp, (long)cl_pid, (long)cl_sysid)) != NULL) {
|
|
msig = (struct message *)bp->b_rptr;
|
|
msig->m_stat |= SIGNAL;
|
|
enque(&rdp->rd_rcvdq, bp);
|
|
rdp->rd_qcnt++;
|
|
add_to_msgs_list(rdp);
|
|
}
|
|
(void) splx(s);
|
|
}
|
|
/* No response message for remote signal request */
|
|
*out_bp = (mblk_t *) NULL;
|
|
|
|
DUPRINT2(DB_SERVE, "rs_rsignal: %s\n", tp ?
|
|
"signalled active server" : "set signal bit in pending requst");
|
|
return (0);
|
|
}
|
|
|
|
/*
|
|
* Invalid op -- shouldn't get these, but just in case return a response to
|
|
* the client.
|
|
*/
|
|
/*ARGSUSED*/
|
|
rs_badop(sp, in_bp, out_bp, outsize, gift)
|
|
struct serv_proc *sp;
|
|
mblk_t *in_bp, **out_bp;
|
|
int *outsize;
|
|
rcvd_t *gift;
|
|
{
|
|
DUPRINT4(DB_SERVE, "rs_badop: sp %x, op %d, rd->vp %x\n",
|
|
sp, sp->s_op, sp->s_rdp->rd_vnode);
|
|
freemsg(in_bp);
|
|
|
|
/* Make response message */
|
|
make_response(sp, (mblk_t **) NULL, EINVAL, (struct vnode *) NULL,
|
|
(struct vattr *) NULL, out_bp, outsize);
|
|
return (-1);
|
|
}
|
|
|
|
/*
|
|
* Get user virtual address space for an rfs server process. Used for doing
|
|
* physio() on raw devices, which doesn't work with data to be moved to/from
|
|
* kernel address space. The address space is created and a zfod() segment
|
|
* of size "size" placed in it. Note that this reserves swap space.
|
|
*/
|
|
struct as *
|
|
rs_getas(size)
|
|
u_int size;
|
|
{
|
|
struct as *as;
|
|
int error;
|
|
|
|
/* Allocate the address space */
|
|
as = as_alloc();
|
|
if (as == NULL)
|
|
goto skip;
|
|
|
|
/* Create a zfod segment in it */
|
|
error = as_map(as, SEGSTART, size, segvn_create, zfod_argsp);
|
|
|
|
if (error) {
|
|
as_free(as);
|
|
as = NULL;
|
|
}
|
|
skip:
|
|
/* Sanity checks */
|
|
if (as == NULL || as->a_segs == NULL ||
|
|
as->a_segs->s_next != as->a_segs ||
|
|
as->a_segs->s_base != SEGSTART) {
|
|
printf("rfs_serve: bad as!\n");
|
|
}
|
|
return (as);
|
|
}
|