📄 psdev.c
字号:
return -EINVAL;}static int presto_psdev_open(struct inode * inode, struct file * file){ struct upc_comm *upccom; ENTRY; if ( ! (upccom = presto_psdev_f2u(file)) ) { kdev_t dev = file->f_dentry->d_inode->i_rdev; printk("InterMezzo: %s, bad device %s\n", __FUNCTION__, kdevname(dev)); EXIT; return -EINVAL; } MOD_INC_USE_COUNT; CDEBUG(D_PSDEV, "Psdev_open: uc_pid: %d, caller: %d, flags: %d\n", upccom->uc_pid, current->pid, file->f_flags); EXIT; return 0;}static int presto_psdev_release(struct inode * inode, struct file * file){ struct upc_comm *upccom; struct upc_req *req; struct list_head *lh; ENTRY; if ( ! (upccom = presto_psdev_f2u(file)) ) { kdev_t dev = file->f_dentry->d_inode->i_rdev; printk("InterMezzo: %s, bad device %s\n", __FUNCTION__, kdevname(dev)); } if ( upccom->uc_pid != current->pid ) { printk("psdev_release: Not lento.\n"); MOD_DEC_USE_COUNT; return 0; } MOD_DEC_USE_COUNT; CDEBUG(D_PSDEV, "Lento: pid %d\n", current->pid); upccom->uc_pid = 0; /* Wake up clients so they can return. */ CDEBUG(D_PSDEV, "Wake up clients sleeping for pending.\n"); lh = &upccom->uc_pending; while ( (lh = lh->next) != &upccom->uc_pending) { req = list_entry(lh, struct upc_req, rq_chain); /* Async requests stay around for a new lento */ if (req->rq_flags & REQ_ASYNC) { continue; } /* the sleeper will free the req and data */ req->rq_flags |= REQ_DEAD; wake_up(&req->rq_sleep); } CDEBUG(D_PSDEV, "Wake up clients sleeping for processing\n"); lh = &upccom->uc_processing; while ( (lh = lh->next) != &upccom->uc_processing) { req = list_entry(lh, struct upc_req, rq_chain); /* freeing of req and data is done by the sleeper */ req->rq_flags |= REQ_DEAD; wake_up(&req->rq_sleep); } CDEBUG(D_PSDEV, "Done.\n"); EXIT; return 0;}static struct file_operations presto_psdev_fops = { read: presto_psdev_read, write: presto_psdev_write, poll: presto_psdev_poll, ioctl: presto_psdev_ioctl, open: presto_psdev_open, release: presto_psdev_release};int presto_psdev_init(void){ int i;#ifdef PRESTO_DEVEL if (register_chrdev(PRESTO_PSDEV_MAJOR, "intermezzo_psdev_devel", &presto_psdev_fops)) { printk(KERN_ERR "presto_psdev: unable to get major %d\n", PRESTO_PSDEV_MAJOR); return -EIO; }#else if (register_chrdev(PRESTO_PSDEV_MAJOR, "intermezzo_psdev", &presto_psdev_fops)) { printk("presto_psdev: unable to get major %d\n", PRESTO_PSDEV_MAJOR); return -EIO; }#endif memset(&upc_comms, 0, sizeof(upc_comms)); for ( i = 0 ; i < MAX_PRESTODEV ; i++ ) { char *name; struct upc_comm *psdev = &upc_comms[i]; INIT_LIST_HEAD(&psdev->uc_pending); INIT_LIST_HEAD(&psdev->uc_processing); INIT_LIST_HEAD(&psdev->uc_cache_list); init_waitqueue_head(&psdev->uc_waitq); psdev->uc_hard = 0; psdev->uc_no_filter = 0; psdev->uc_no_journal = 0; psdev->uc_no_upcall = 0; psdev->uc_timeout = 30; psdev->uc_errorval = 0; psdev->uc_minor = i; PRESTO_ALLOC(name, char *, strlen(PRESTO_PSDEV_NAME "256")+1); if (!name) { printk("Unable to allocate memory for device name\n"); continue; } sprintf(name, PRESTO_PSDEV_NAME "%d", i); psdev->uc_devname = name; } return 0;}void presto_psdev_cleanup(void){ int i; for ( i = 0 ; i < MAX_PRESTODEV ; i++ ) { struct upc_comm *psdev = &upc_comms[i]; struct list_head *lh; if ( ! list_empty(&psdev->uc_pending)) { printk("Weird, tell Peter: module cleanup and pending list not empty dev %d\n", i); } if ( ! list_empty(&psdev->uc_processing)) { printk("Weird, tell Peter: module cleanup and processing list not empty dev %d\n", i); } if ( ! list_empty(&psdev->uc_cache_list)) { printk("Weird, tell Peter: module cleanup and cache listnot empty dev %d\n", i); } if (psdev->uc_devname) { PRESTO_FREE(psdev->uc_devname, strlen(PRESTO_PSDEV_NAME "256")+1); } lh = psdev->uc_pending.next; while ( lh != &psdev->uc_pending) { struct upc_req *req; req = list_entry(lh, struct upc_req, rq_chain); lh = lh->next; if ( req->rq_flags & REQ_ASYNC ) { list_del(&(req->rq_chain)); CDEBUG(D_UPCALL, "free pending upcall type %d\n", req->rq_opcode); PRESTO_FREE(req->rq_data, req->rq_bufsize); PRESTO_FREE(req, sizeof(struct upc_req)); } else { req->rq_flags |= REQ_DEAD; wake_up(&req->rq_sleep); } } lh = &psdev->uc_processing; while ( (lh = lh->next) != &psdev->uc_processing ) { struct upc_req *req; req = list_entry(lh, struct upc_req, rq_chain); list_del(&(req->rq_chain)); req->rq_flags |= REQ_DEAD; wake_up(&req->rq_sleep); } }}/* * lento_upcall and lento_downcall routines */static inline unsigned long lento_waitfor_upcall(struct upc_req *req, int minor){ DECLARE_WAITQUEUE(wait, current); unsigned long posttime; req->rq_posttime = posttime = jiffies; add_wait_queue(&req->rq_sleep, &wait); for (;;) { if ( upc_comms[minor].uc_hard == 0 ) current->state = TASK_INTERRUPTIBLE; else current->state = TASK_UNINTERRUPTIBLE; /* got a reply */ if ( req->rq_flags & (REQ_WRITE | REQ_DEAD) ) break; if ( !upc_comms[minor].uc_hard && signal_pending(current) ) { /* if this process really wants to die, let it go */ if (sigismember(&(current->pending.signal), SIGKILL)|| sigismember(&(current->pending.signal), SIGINT) ) break; /* signal is present: after timeout always return really smart idea, probably useless ... */ if ( time_after(jiffies, req->rq_posttime + upc_comms[minor].uc_timeout * HZ) ) break; } schedule(); } list_del(&req->rq_chain); INIT_LIST_HEAD(&req->rq_chain); remove_wait_queue(&req->rq_sleep, &wait); current->state = TASK_RUNNING; CDEBUG(D_SPECIAL, "posttime: %ld, returned: %ld\n", posttime, jiffies-posttime); return (jiffies - posttime);}/* * lento_upcall will return an error in the case of * failed communication with Lento _or_ will peek at Lento * reply and return Lento's error. * * As lento has 2 types of errors, normal errors (positive) and internal * errors (negative), normal errors are negated, while internal errors * are all mapped to -EINTR, while showing a nice warning message. (jh) * * lento_upcall will always free buffer, either directly, when an upcall * is read (in presto_psdev_read), when the filesystem is unmounted, or * when the module is unloaded. */int lento_upcall(int minor, int bufsize, int *rep_size, union up_args *buffer, int async, struct upc_req *rq){ unsigned long runtime; struct upc_comm *upc_commp; union down_args *out; struct upc_req *req; int error = 0; ENTRY; upc_commp = &(upc_comms[minor]); if (upc_commp->uc_no_upcall) { EXIT; goto exit_buf; } if (!upc_commp->uc_pid && !async) { EXIT; error = -ENXIO; goto exit_buf; } /* Format the request message. */ CDEBUG(D_UPCALL, "buffer at %p, size %d\n", buffer, bufsize); PRESTO_ALLOC(req, struct upc_req *, sizeof(struct upc_req)); if ( !req ) { EXIT; error = -ENOMEM; goto exit_buf; } req->rq_data = (void *)buffer; req->rq_flags = 0; req->rq_bufsize = bufsize; req->rq_rep_size = 0; req->rq_opcode = ((union up_args *)buffer)->uh.opcode; req->rq_unique = ++upc_commp->uc_seq; init_waitqueue_head(&req->rq_sleep); /* Fill in the common input args. */ ((union up_args *)buffer)->uh.unique = req->rq_unique; /* Append msg to pending queue and poke Lento. */ list_add(&req->rq_chain, upc_commp->uc_pending.prev); CDEBUG(D_UPCALL, "Proc %d waking Lento %d for(opc,uniq) =(%d,%d) msg at %p.\n", current->pid, upc_commp->uc_pid, req->rq_opcode, req->rq_unique, req); wake_up_interruptible(&upc_commp->uc_waitq); if ( async ) { req->rq_flags = REQ_ASYNC; if( rq != NULL ) { *rq = *req; /* struct copying */ } /* req, rq_data are freed in presto_psdev_read for async */ EXIT; return 0; } /* We can be interrupted while we wait for Lento to process * our request. If the interrupt occurs before Lento has read * the request, we dequeue and return. If it occurs after the * read but before the reply, we dequeue, send a signal * message, and return. If it occurs after the reply we ignore * it. In no case do we want to restart the syscall. If it * was interrupted by a lento shutdown (psdev_close), return * ENODEV. */ /* Go to sleep. Wake up on signals only after the timeout. */ runtime = lento_waitfor_upcall(req, minor); CDEBUG(D_TIMING, "opc: %d time: %ld uniq: %d size: %d\n", req->rq_opcode, jiffies - req->rq_posttime, req->rq_unique, req->rq_rep_size); CDEBUG(D_UPCALL, "..process %d woken up by Lento for req at 0x%p, data at %p\n", current->pid, req, req->rq_data); if (upc_commp->uc_pid) { /* i.e. Lento is still alive */ /* Op went through, interrupt or not we go on */ if (req->rq_flags & REQ_WRITE) { out = (union down_args *)req->rq_data; /* here we map positive Lento errors to kernel errors */ if ( out->dh.result < 0 ) { printk("Tell Peter: Lento returns negative error %d, for oc %d!\n", out->dh.result, out->dh.opcode); out->dh.result = EINVAL; } error = -out->dh.result; CDEBUG(D_UPCALL, "upcall: (u,o,r) (%d, %d, %d) out at %p\n", out->dh.unique, out->dh.opcode, out->dh.result, out); *rep_size = req->rq_rep_size; EXIT; goto exit_req; } /* Interrupted before lento read it. */ if ( !(req->rq_flags & REQ_READ) && signal_pending(current)) { CDEBUG(D_UPCALL, "Interrupt before read: (op,un)=(%d,%d), flags %x\n", req->rq_opcode, req->rq_unique, req->rq_flags); /* perhaps the best way to convince the app to give up? */ error = -EINTR; EXIT; goto exit_req; } /* interrupted after Lento did its read, send signal */ if ( (req->rq_flags & REQ_READ) && signal_pending(current) ) { union up_args *sigargs; struct upc_req *sigreq; CDEBUG(D_UPCALL,"Sending for: op = %d.%d, flags = %x\n", req->rq_opcode, req->rq_unique, req->rq_flags); error = -EINTR; /* req, rq_data are freed in presto_psdev_read for async */ PRESTO_ALLOC(sigreq, struct upc_req *, sizeof (struct upc_req)); if (!sigreq) { error = -ENOMEM; EXIT; goto exit_req; } PRESTO_ALLOC((sigreq->rq_data), char *, sizeof(struct lento_up_hdr)); if (!(sigreq->rq_data)) { PRESTO_FREE(sigreq, sizeof (struct upc_req)); error = -ENOMEM; EXIT; goto exit_req; } sigargs = (union up_args *)sigreq->rq_data; sigargs->uh.opcode = LENTO_SIGNAL; sigargs->uh.unique = req->rq_unique; sigreq->rq_flags = REQ_ASYNC; sigreq->rq_opcode = sigargs->uh.opcode; sigreq->rq_unique = sigargs->uh.unique; sigreq->rq_bufsize = sizeof(struct lento_up_hdr); sigreq->rq_rep_size = 0; CDEBUG(D_UPCALL, "presto_upcall: enqueing signal msg (%d, %d)\n", sigreq->rq_opcode, sigreq->rq_unique); /* insert at head of queue! */ list_add(&sigreq->rq_chain, &upc_commp->uc_pending); wake_up_interruptible(&upc_commp->uc_waitq); } else { printk("Lento: Strange interruption - tell Peter.\n"); error = -EINTR; } } else { /* If lento died i.e. !UC_OPEN(upc_commp) */ printk("presto_upcall: Lento dead on (op,un) (%d.%d) flags %d\n", req->rq_opcode, req->rq_unique, req->rq_flags); error = -ENODEV; }exit_req: PRESTO_FREE(req, sizeof(struct upc_req));exit_buf: PRESTO_FREE(buffer, bufsize); return error;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -