📄 connld.c
字号:
/* * connld.c - unique pipe generator * * On the first open of this module, a connection to it's stream head * is made, but nothing else. On subsequent calls, however, the open * does the following: * . generate a unique pipe * . return one endpoint of the pipe to replace itself, i.e, by returning * the near endpoint's device number * . send the far endpoint's file via an M_PASSFP message to the * the far endpoint of its own pipe, to be picked up via an * I_RECVFD ioctl. * Thus, this module can only be pushed on a pipe (not even on * a single-ended FIFO). * * Note that this module will never handle message traffic. * * Copyright (C) 2000 John A. Boyd Jr. protologos, LLC * * 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. */#ident "@(#) LiS connld.c 1.10 09/24/03"#include <linux/config.h>#include <linux/version.h>#ifdef CONFIG_MODVERSIONS#include <linux/modversions.h>#endif#include <linux/module.h>#include <sys/LiS/config.h>#include <sys/stream.h>#include <sys/stropts.h>#include <linux/errno.h>#include <sys/cmn_err.h>#include <sys/LiS/head.h>#include <sys/osif.h>/* * Some configuration sanity checks */#ifndef CONNLD_#error Not configured#endif#ifndef CONNLD__ID#define CONNLD__ID 0xaabc#endif#define MOD_ID CONNLD__ID#define MOD_NAME "connld"/* * function prototypes */static int connld_open(queue_t *, dev_t*, int, int, cred_t *);static int connld_close(queue_t *, int, cred_t *);static int connld_wput( queue_t *q, mblk_t *mp );static int connld_rput( queue_t *q, mblk_t *mp );/* * module structure */static struct module_info connld_minfo ={ MOD_ID, /* id */ MOD_NAME, /* name */ 0, /* min packet size accepted */ INFPSZ, /* max packet size accepted */ 10240L, /* highwater mark */ 512L /* lowwater mark */};static struct qinit connld_rinit = { connld_rput, /* put */ NULL, /* service */ connld_open, /* open */ connld_close, /* close */ NULL, /* admin */ &connld_minfo, /* info */ NULL /* stat */};static struct qinit connld_winit = { connld_wput, /* put */ NULL, /* service */ NULL, /* open */ NULL, /* close */ NULL, /* admin */ &connld_minfo, /* info */ NULL /* stat */};struct streamtab connld_info ={ &connld_rinit, /* read queue init */ &connld_winit, /* write queue init */ NULL, /* lower mux read queue init */ NULL /* lower mux write queue init */};/* * open */static int connld_open( q, devp, flag, sflag, credp )queue_t *q;dev_t *devp;int flag, sflag;cred_t *credp;{ stdata_t *head = q->q_str; if (!head || head->magic != STDATA_MAGIC) { cmn_err( CE_CONT, "connld_open(): bad reference to stream head\n" ); return -EINVAL; } if (!F_ISSET(head->sd_flag, STFIFO)) { cmn_err( CE_CONT, "connld_open(): not even a FIFO!!\n" ); return -EPIPE; } if (!head->sd_peer || head->sd_peer == head) { cmn_err( CE_CONT, "connld_open(): this STREAM just is a FIFO, not a pipe\n" ); return -EPIPE; }#ifdef DEBUG cmn_err( CE_CONT, "connld_open(q@0x%p, 0x%x, 0x%x,0x%x, ...)#%d " "h@0x%p/%d/%d f@0x%p/%d\n", q, *devp, flag, sflag, (int)q->q_ptr, head, (head?LIS_SD_REFCNT(head):0), (head?LIS_SD_OPENCNT(head):0), head->sd_file, (head->sd_file?F_COUNT(head->sd_file):0) );#endif if (q->q_ptr) { struct file *f0, *f1, *oldf = head->sd_file; int error; if (head != FILE_STR(oldf)) { cmn_err( CE_CONT, "connld_open(): invalid sd_file 0x%p\n", head->sd_file ); return -EINVAL; }#ifdef DEBUG cmn_err( CE_CONT, "connld_open(): opening file@0x%p/%d - creating pipe...\n", oldf, (oldf?F_COUNT(oldf):0) );#endif if ((error = lis_get_pipe( &f0, &f1 )) < 0) { cmn_err( CE_CONT, "connld_open(): get_pipe() failed: %d\n", error ); return error; }#ifdef DEBUG cmn_err( CE_CONT, "connld_open(...)" " >> pipe 0x%x(h@0x%p/%d/%d) <=X=> 0x%x(h@0x%p/%d/%d)\n", FILE_INODE(f0)->i_rdev, FILE_STR(f0), LIS_SD_REFCNT(FILE_STR(f0)), LIS_SD_OPENCNT(FILE_STR(f0)), FILE_INODE(f1)->i_rdev, FILE_STR(f1), LIS_SD_REFCNT(FILE_STR(f1)), LIS_SD_OPENCNT(FILE_STR(f1)) );#endif /* * send one of the new pipe's ends to the peer of the connld pipe */ if ((error = lis_sendfd( head, -1, f1 )) < 0) { cmn_err( CE_CONT, "connld_open(): sendfd(h@0x%p,-1,f@0x%p) failed - %d\n", head, f1, error ); lis_strclose( FILE_INODE(f0), f0 ); lis_strclose( FILE_INODE(f1), f1 ); return error; } /* * replace the current opening file's inode */ if (!lis_old_inode( oldf, FILE_INODE(f0) )) { lis_strclose( FILE_INODE(f0), f0 ); return -EINVAL; } /* * we now have an unused file pointer to the new pipe end (f0) * we must discard, and we need to get all the reference counts * right for both the original and the new pipe end (net change: * old pipe end: refcnt--, new pipe end: opencnt--) so that * the stropen in progress will finish appropriately using the * new pipe end, with the original left as if no open was even * attempted. * * FIXME: stropen() is holding head->sd_opening when it calls * open_mods(), which gets us here, but doclose also tries to * hold it. To prevent a deadlock, I'm switching the lock here * from the old head to the new one, leaving it open during the * intervening fput(), but it might be better to have stropen * call open_mods() with no locks held... Dave?... - JB 12/6/02 */ { struct stdata *oldhead = head; *devp = KDEV_TO_INT(FILE_INODE(f0)->i_rdev); lis_atomic_dec(&oldhead->sd_refcnt); head = FILE_STR(f0); SET_FILE_STR(oldf, head); lis_up(&oldhead->sd_opening); /* release this before fput */ lis_atomic_inc(&head->sd_refcnt); lis_atomic_inc(&head->sd_opencnt); /* prevent opencnt->0 */ fput(f0); /* calls strclose */ lis_atomic_dec(&head->sd_opencnt); lis_down(&head->sd_opening);#ifdef DEBUG cmn_err( CE_CONT, "connld_open(...)" " >> replaced h@0x%p/--%d/%d -> h@0x%p/%d/--%d\n", oldhead, LIS_SD_REFCNT(oldhead), LIS_SD_OPENCNT(oldhead), head, LIS_SD_REFCNT(head), LIS_SD_OPENCNT(head));#endif }#ifdef DEBUG cmn_err( CE_CONT, "connld_open(q@0x%xp, 0x%x, 0x%x,0x%x, ...)#%d " "head@0x%p/%d/%d OK\n", q, *devp, flag, sflag, (int)q->q_ptr, head, LIS_SD_REFCNT(head), LIS_SD_OPENCNT(head) );#endif return 0; } else { /* * first time in - check STCONNLD flag, then set it */ if (F_ISSET(head->sd_flag,STCONNLD)) { cmn_err( CE_CONT, "connld_open(): previously pushed 'connld'\n" ); return -EINVAL; } SET_SD_FLAG(head,STCONNLD); /* * set q_ptr as an open count flag */ ((char *)q->q_ptr)++; MOD_INC_USE_COUNT; return 0; }}/* * close */static int connld_close( q, flag, credp )queue_t *q;int flag;cred_t *credp;{ stdata_t *head = q->q_str;#ifdef DEBUG cmn_err( CE_CONT, "connld_close(q@0x%p, 0x%x, ...) head 0x%p\n", q, flag, head );#endif q->q_ptr = NULL;#ifdef MODULE MOD_DEC_USE_COUNT;#endif qprocsoff(q); if (!head || head->magic != STDATA_MAGIC) { cmn_err( CE_CONT, "connld_open(): bad reference to stream head\n" ); return -EINVAL; } CLR_SD_FLAG(head,STCONNLD); return 0;} /* * wput */static int connld_wput( queue_t *q, mblk_t *mp ){ /* * connld is a module, but will at the bottom of a STREAM, * like a driver. Thus, IOCTLs must be NAK'ed, like a driver, * not passed down, like a module. Otherwise, STREAMS might * hang waiting for the IOCTL response message. * * connld should not be expected to process any other message * traffic, so we discard all other messages. */ switch (mp->b_datap->db_type) { case M_IOCTL: if (q->q_next && SAMESTR(q->q_next)) { putnext( q, mp ); } else { mp->b_datap->db_type = M_IOCNAK; qreply( q, mp ); } break; default:#ifdef DEBUG cmn_err( CE_CONT, "connld_wput(q@0x%p,m@0x%p) message discarded\n", q, mp );#endif freemsg(mp); break; } return 0;}/* * rput */static int connld_rput( queue_t *q, mblk_t *mp ){ putnext( q, mp ); return 0;}#ifdef MODULE/* * Linux loadable module interface */int init_module(void){ int ret = lis_register_strmod( &connld_info, MOD_NAME ); if (ret < 0) { cmn_err( CE_CONT, "%s - unable to register module.\n", MOD_NAME ); return ret; } return 0;}void cleanup_module(void){ if (lis_unregister_strmod(&connld_info) < 0) cmn_err( CE_CONT, "%s - unable to unregister module.\n", MOD_NAME ); return;}#endif#if defined(LINUX) /* linux kernel */#if defined(MODULE_LICENSE)MODULE_LICENSE("GPL and additional rights");#endif#if defined(MODULE_AUTHOR)MODULE_AUTHOR("John A. Boyd Jr");#endif#if defined(MODULE_DESCRIPTION)MODULE_DESCRIPTION("STREAMS unique pipe generator");#endif#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -