📄 loop.c
字号:
/* -*- Mode: C -*- * loop.c --- Streams loopback driver, as of Sun manual * Author : Graham Wheeler * Created On : Sat Oct 7 05:01:31 1995 * Last Modified By: David Grothe * RCS Id : loop.c,v 1.1.1.2.8.1 2004/01/12 23:32:39 brian Exp * Purpose : provide loopback streams driver * ----------------______________________________________________ * * Copyright (C) 1995 Graham Wheeler, Francisco J. Ballesteros, * Copyright (C) 1997 David Grothe, Gcom, Inc <dave@gcom.com> * * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, Cambridge, * MA 02139, USA. * * * You can reach us by email to any of * gram@aztec.co.za, nemo@ordago.uc3m.es */#ident "@(#) LiS loop.c 2.23 10/23/03 21:23:58 "/* ------------------------------------------------------------------- */#include <sys/stream.h>#include <sys/stropts.h>#include <linux/stat.h> /* for S_IFCHR */#include <sys/osif.h>/* ------------------------------------------------------------------- *//* Module definition structs *//* Module info for the loopback driver */static struct module_info loop_minfo = { 0, /* id */ "loop", /* name */ 0, /* min packet size accepted */ INFPSZ, /* max packet size accepted */ 10240L, /* high water mark */ 512L /* low water mark */};/* These are the entry points to the driver: open, close, write side put and * service procedures and read side service procedure. */static int loop_open(queue_t *, dev_t *, int, int, cred_t *);static int loop_close(queue_t *, int, cred_t *);static int loop_wput(queue_t *, mblk_t *);static int loop_wsrv(queue_t *);static int loop_rsrv(queue_t *);/* qinit structures (rd and wr side) */static struct qinit loop_rinit = { NULL, /* put */ loop_rsrv, /* service */ loop_open, /* open */ loop_close, /* close */ NULL, /* admin */ &loop_minfo, /* info */ NULL /* stat */};static struct qinit loop_winit = { loop_wput, /* put */ loop_wsrv, /* service */ NULL, /* open */ NULL, /* close */ NULL, /* admin */ &loop_minfo, /* info */ NULL /* stat */};/* streamtab for the loopback driver. */struct streamtab sloop_info = { &loop_rinit, /* read queue */ &loop_winit, /* write queue */ NULL, /* mux read queue */ NULL /* mux write queue */};/* ------------------------------------------------------------------- *//* Module implementation */#include <sys/LiS/loop.h>/* ------------------------------------------------------------------- */#define NLOOP 21 /* number of clone devs supported */struct loop /* info for each loopback device */{ queue_t *qptr; queue_t *oqptr; int use_putnext; /* instead of service queue */ int use_bufcall; /* instead of putnext */ int msglvl; /* # msgs to queue before sending upstream */ int msgcnt; /* # msgs in the queue */ int timr; /* time out amount while msgs queued */ toid_t timr_hndl; /* for running timer */ int mark; /* "mark" the next message(s) from above */ int minor_nr; /* minor number of this instance */ int catlvl; /* # msgs to concat before sending upstream */ int copy_bfr; /* copy the message before looping */ mblk_t *saved_msg; /* msg saved for contatenation */ char *copy_buf; /* for copyin/out */ int copy_buf_size; /* length of copy_buf data */ loop_xparent_t xp; /* copied in from user space */ int deny_2nd_open; /* deny a subsequent open of this minor */ int burst; /* send a burst of messages upstream */};/* Arry. w/ opened devices info & number of openened devices */static struct loop loop_loop[NLOOP];static int loop_cnt = NLOOP;/* ------------------------------------------------------------------- */static void make_node(char *name, int maj, int mnr){ int rtn; rtn = lis_unlink(name); if (rtn < 0 && rtn != -ENOENT) { printk("unlink %s: error %d\n", name, rtn); return ; } if (maj == 0) /* don't make the node */ { printk("unlink %s: OK\n", name); return ; } rtn = lis_mknod(name, 0666 | S_IFCHR, MKDEV(maj, mnr)); if (rtn == 0) printk("mknod %s: OK\n", name); else printk("mknod %s: error %d\n", name, rtn);}void sloop_init(void){ make_node("/dev/loop_clone", CLONE__CMAJOR_0, SLOOP__CMAJOR_0); make_node("/dev/loop.1", SLOOP__CMAJOR_0, 1); make_node("/dev/loop.2", SLOOP__CMAJOR_0, 2); make_node("/dev/loop.9", SLOOP__CMAJOR_0, 9); make_node("/dev/loop.255", SLOOP__CMAJOR_0, 255);} /* loop_init */void sloop_term(void){ make_node("/dev/loop_clone", 0,0); make_node("/dev/loop.1", 0,0); make_node("/dev/loop.2", 0,0); make_node("/dev/loop.9", 0,0); make_node("/dev/loop.255", 0,0);} /* loop_term *//* ------------------------------------------------------------------- */static intloop_open(queue_t * q, dev_t * devp, int flag, int sflag, cred_t * credp){ struct loop *loop; int dev; if (sflag == CLONEOPEN) { for (dev = 1; dev < loop_cnt; dev++) { if (loop_loop[dev].qptr == NULL) break; } } else dev = MINOR(*devp); if (dev >= loop_cnt) return -ENODEV; loop = &loop_loop[dev]; *devp = MKDEV(MAJOR(*devp), dev); if (q->q_ptr) /* already open */ { if (loop->deny_2nd_open) return -EBUSY; return 0; /* success */ } WR(q)->q_ptr = (char *) loop; q->q_ptr = (char *) loop; loop->qptr = WR(q); loop->minor_nr = dev; MOD_INC_USE_COUNT; return 0; /* success */}/* ------------------------------------------------------------------- */static void loop_timeout(caddr_t arg){ struct loop *loop = (struct loop *) arg; if (loop->qptr != NULL) { enableok(WR(loop->qptr)); /* allow qenable to work */ qenable(WR(loop->qptr)); }} /* loop_timeout *//* ------------------------------------------------------------------- *//* * loop_bufcall * * Called from the STREAMS bufcall mechanism. * * The argument is a pointer to a queue to enable. */static void loop_bufcall(long q_ptr){ enableok((queue_t *) q_ptr); /* allow qenable to work */ qenable((queue_t *) q_ptr);} /* loop_bufcall *//* ------------------------------------------------------------------- *//* * Concatenate the given message with the "saved" message in the * loop structure. This allows the user to build multi-segment * messages that later get sent upstream. */static mblk_t *loop_concat(struct loop *loop, mblk_t * mp){ mblk_t *lastmp; if (loop->saved_msg == NULL) { loop->saved_msg = mp; return (mp); } for (lastmp = loop->saved_msg; lastmp->b_cont != NULL; lastmp = lastmp->b_cont) ; lastmp->b_cont = mp; /* hook new onto saved msg */ mp = loop->saved_msg; /* mp becomes new concatenated msg */ loop->saved_msg = NULL; /* no longer saved */ return (mp); /* return entire message */} /* loop_concat *//* ------------------------------------------------------------------- */int loop_request_copyio(queue_t * wq, struct loop *loop, mblk_t * mp, int msg_type, void *uptr, int nbytes){ struct copyreq *rq = (struct copyreq *) mp->b_rptr; mblk_t *dp = mp->b_cont; mp->b_wptr = mp->b_rptr + sizeof(*rq); rq->cq_addr = uptr; rq->cq_size = nbytes; rq->cq_flag = 0; rq->cq_private = (mblk_t *) loop; if (dp != NULL && msg_type == M_COPYIN) { mp->b_cont = NULL; /* discard data */ freemsg(dp); } mp->b_datap->db_type = msg_type; /* M_COPYIN or M_COPYOUT */ qreply(wq, mp); return (0);} /* loop_request_copyio *//* ------------------------------------------------------------------- */int loop_iocdata(queue_t * wq, mblk_t * mp){ struct copyresp *rsp = (struct copyresp *) mp->b_rptr; struct loop *loop = (struct loop *) rsp->cp_private; struct iocblk *iocb; iocb = (struct iocblk *) rsp; switch (rsp->cp_cmd) { case LOOP_XPARENT_COPYIN: case LOOP_XPARENT_COPYOUT: { mblk_t *dp; dp = mp->b_cont; if (rsp->cp_rval != 0) { printk("loop_iocdata: copyin request failed\n"); return (-EINVAL); } if (dp == NULL || dp->b_datap->db_type != M_DATA) { printk("loop_iocdata: attached bfr NULL or not M_DATA\n"); return (-EINVAL); } if (msgdsize(dp) != sizeof(loop_xparent_t)) { printk("loop_iocdata: expected %d bytes, got %d\n", sizeof(loop_xparent_t), msgdsize(dp)); return (-EINVAL); } loop->xp = *((loop_xparent_t *) dp->b_rptr); mp->b_cont = NULL; freemsg(dp); /* * If we fetched the xparent struct for a copy in then issue * another copy in for the actual data from user space. * If it was for a copy out then return the requested data * in an M_DATA and request it to be copied out to the user's * space. * * Alter the command by oring in an 0xf00 so that when the * iocdata for these requests comes down we can tell that * they are for the final copy functions. Handled in separate * cases below. */ switch (rsp->cp_cmd) { case LOOP_XPARENT_COPYIN: rsp->cp_cmd |= 0xf00; /* alter the command */ if (loop_request_copyio(wq, loop, mp, M_COPYIN, loop->xp.p_arg, loop->xp.i_arg) < 0) { printk("loop_iocdata: loop_request_copyio failed\n"); return (-EINVAL); } return (1); /* keep exchanging msgs w/strm hd */ case LOOP_XPARENT_COPYOUT: if (loop->copy_buf == NULL) return (-EINVAL); if (loop->copy_buf_size < loop->xp.i_arg) loop->xp.i_arg = loop->copy_buf_size; dp = allocb(loop->xp.i_arg, BPRI_LO); if (dp == NULL) return (-ENOMEM); memcpy(dp->b_wptr, loop->copy_buf, loop->xp.i_arg); dp->b_wptr += loop->xp.i_arg; linkb(mp, dp); rsp->cp_cmd |= 0xf00; /* alter the command */ if (loop_request_copyio(wq, loop, mp, M_COPYOUT, loop->xp.p_arg, loop->xp.i_arg) < 0) { printk("loop_iocdata: loop_request_copyio failed\n"); return (-EINVAL); } return (1); /* keep exchanging msgs w/strm hd */ } break; } /* * This is the actual data that the user wanted us to copy in. */ case LOOP_XPARENT_COPYIN | 0xf00: { mblk_t *dp; dp = mp->b_cont; if (rsp->cp_rval != 0) { printk("loop_iocdata: copyin request failed\n"); return (-EINVAL); } if (dp == NULL || dp->b_datap->db_type != M_DATA) { printk("loop_iocdata: attached bfr NULL or not M_DATA\n"); return (-EINVAL); } if (msgdsize(dp) != loop->xp.i_arg) { printk("loop_iocdata: expected %d bytes, got %d\n", loop->xp.i_arg, msgdsize(dp)); return (-1); } if (loop->copy_buf != NULL) FREE(loop->copy_buf); loop->copy_buf = MALLOC(loop->xp.i_arg); if (loop->copy_buf == NULL) return (-ENOMEM); memcpy(loop->copy_buf, dp->b_rptr, loop->xp.i_arg); loop->copy_buf_size = loop->xp.i_arg; return (0); /* send iocack now */ } /* * This is the result of copying out data to the user. */ case LOOP_XPARENT_COPYOUT | 0xf00: { if (rsp->cp_rval != 0) { printk("loop_iocdata: copyin request failed\n"); return (-EINVAL); } return (0); /* send iocack now */ } default: printk("loop_iocdata: cmd=0x%x unknown\n", rsp->cp_cmd); return (-EINVAL); } return (0);} /* loop_iocdata *//* ------------------------------------------------------------------- */static int loop_wput(queue_t * q, mblk_t * mp){ struct loop *loop; int rtn_count = 0;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -