diff -NBbru linux-2.4.6.vanilla/Makefile linux-2.4.6/Makefile --- linux-2.4.6.vanilla/Makefile Wed Jul 4 10:44:28 2001 +++ linux-2.4.6/Makefile Wed Jul 4 10:48:53 2001 @@ -1,7 +1,7 @@ VERSION = 2 PATCHLEVEL = 4 SUBLEVEL = 6 -EXTRAVERSION = +EXTRAVERSION = dp01 KERNELRELEASE=$(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION) diff -NBbru linux-2.4.6.vanilla/drivers/char/Config.in linux-2.4.6/drivers/char/ Config.in --- linux-2.4.6.vanilla/drivers/char/Config.in Wed Jul 4 10:44:34 2001 +++ linux-2.4.6/drivers/char/Config.in Wed Jul 4 10:45:58 2001 @@ -158,6 +158,7 @@ dep_tristate 'Intel i8x0 Random Number Generator support' CONFIG_INTEL_RNG $CON FIG_PCI tristate '/dev/nvram support' CONFIG_NVRAM +tristate '/dev/poll support' CONFIG_DEVPOLL tristate 'Enhanced Real Time Clock Support' CONFIG_RTC if [ "$CONFIG_IA64" = "y" ]; then bool 'EFI Real Time Clock Services' CONFIG_EFI_RTC diff -NBbru linux-2.4.6.vanilla/drivers/char/Makefile linux-2.4.6/drivers/char/M akefile --- linux-2.4.6.vanilla/drivers/char/Makefile Wed May 16 10:27:02 2001 +++ linux-2.4.6/drivers/char/Makefile Mon Jul 2 18:55:01 2001 @@ -173,6 +173,7 @@ ifeq ($(CONFIG_PPC),) obj-$(CONFIG_NVRAM) += nvram.o endif +obj-$(CONFIG_DEVPOLL) += devpoll.o obj-$(CONFIG_TOSHIBA) += toshiba.o obj-$(CONFIG_DS1620) += ds1620.o obj-$(CONFIG_INTEL_RNG) += i810_rng.o diff -NBbru linux-2.4.6.vanilla/drivers/char/devpoll.c linux-2.4.6/drivers/char/ devpoll.c --- linux-2.4.6.vanilla/drivers/char/devpoll.c Wed Dec 31 16:00:00 1969 +++ linux-2.4.6/drivers/char/devpoll.c Mon Jul 9 19:20:39 2001 @@ -0,0 +1,732 @@ +/* + * + * /dev/poll support + * by Davide Libenzi + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + + + + + +#define DEBUG 0 +#ifdef DEBUG +#define DPRINTK(x) printk x +#define DNPRINTK(n,x) if (n <= DEBUG) printk x +#else +#define DPRINTK(x) +#define DNPRINTK(n,x) +#endif + +#define DEBUG_DPI 0 + +#if DEBUG_DPI +#define DPI_SLAB_DEBUG (SLAB_DEBUG_FREE | SLAB_RED_ZONE /* | SLAB_POISON */) +#else +#define DPI_SLAB_DEBUG 0 +#endif + +#define INITIAL_HASH_BITS 7 +#define MAX_HASH_BITS 16 +#define RESIZE_LENGTH 2 + +#define dpi_mem_alloc() (struct dpitem *) kmem_cache_alloc(dpi_cache, SLAB_KERN EL) +#define dpi_mem_free(p) kmem_cache_free(dpi_cache, p) + + + + + +typedef unsigned long long event_version_t; + +struct devpoll { + rwlock_t lock; + wait_queue_head_t wq; + atomic_t sleepers; + struct list_head *hash; + unsigned int hbits; + unsigned int hmask; + atomic_t hents; + int numpages; + char **pages; + char *pages0[MAX_DEVPOLL_PAGES]; + char *pages1[MAX_DEVPOLL_PAGES]; + atomic_t mmapped; + int eventcnt; + event_version_t ver; + int minevents; + unsigned long minjiffies; + unsigned long jiffies; + +}; + +struct dpitem { + struct list_head lnk; + struct devpoll *dp; + struct pollfd pfd; + int index; + event_version_t ver; + +}; + + + + + + +static int dp_alloc_pages(char **pages, int numpages); +static int dp_free_pages(char **pages, int numpages); +static int dp_init(struct devpoll *dp); +static void dp_free(struct devpoll *dp); +static struct dpitem *dp_find(struct devpoll *dp, int fd); +static int dp_hashresize(struct devpoll *dp); +static int dp_insert(struct devpoll *dp, struct pollfd *pfd); +static int dp_remove(struct devpoll *dp, struct dpitem *dpi); +static void notify_proc(struct file *file, void *data, unsigned long *local, lo ng *event); +static int open_devpoll(struct inode *inode, struct file *file); +static int close_devpoll(struct inode *inode, struct file *file); +static int write_devpoll(struct file *file, const char *buffer, size_t count, + loff_t *ppos); +static int dp_poll(struct devpoll *dp, void *arg); +static int ioctl_devpoll(struct inode *inode, struct file *file, + unsigned int cmd, unsigned long arg); +static void devpoll_mm_open(struct vm_area_struct * vma); +static void devpoll_mm_close(struct vm_area_struct * vma); +static int mmap_devpoll(struct file *file, struct vm_area_struct *vma); + + + + +static kmem_cache_t *dpi_cache; + +static struct file_operations devpoll_fops = { + write: write_devpoll, + ioctl: ioctl_devpoll, + mmap: mmap_devpoll, + open: open_devpoll, + release: close_devpoll +}; + +static struct vm_operations_struct devpoll_mmap_ops = { + open: devpoll_mm_open, + close: devpoll_mm_close, +}; + +static struct miscdevice devpoll = { + DEVPOLL_MINOR, "devpoll", &devpoll_fops +}; + + + + +static int dp_alloc_pages(char **pages, int numpages) +{ + int ii; + + for (ii = 0; ii < numpages; ii++) { + pages[ii] = (char *) __get_free_pages(GFP_KERNEL, 0); + if (!pages[ii]) { + for (--ii; ii >= 0; ii--) { + clear_bit(PG_reserved, &virt_to_page(pages[ii])->flags); + free_pages((unsigned long) pages[ii], 0); + } + return -ENOMEM; + } + set_bit(PG_reserved, &virt_to_page(pages[ii])->flags); + } + return 0; +} + + +static int dp_free_pages(char **pages, int numpages) +{ + int ii; + + for (ii = 0; ii < numpages; ii++) { + clear_bit(PG_reserved, &virt_to_page(pages[ii])->flags); + free_pages((unsigned long) pages[ii], 0); + } + return 0; +} + + +static int dp_init(struct devpoll *dp) +{ + int ii, hentries; + + rwlock_init(&dp->lock); + init_waitqueue_head(&dp->wq); + atomic_set(&dp->sleepers, 0); + dp->hbits = INITIAL_HASH_BITS; + dp->hmask = (1 << dp->hbits) - 1; + atomic_set(&dp->hents, 0); + atomic_set(&dp->mmapped, 0); + dp->numpages = 0; + dp->pages = NULL; + dp->eventcnt = 0; + dp->ver = 1; + dp->minevents = 0; + dp->minjiffies = 0; + dp->jiffies = 0; + + hentries = dp->hmask + 1; + if (!(dp->hash = (struct list_head *) kmalloc(hentries * sizeof(struct list_he ad), + GFP_KERNEL))) + return -ENOMEM; + + for (ii = 0; ii < hentries; ii++) + INIT_LIST_HEAD(&dp->hash[ii]); + + return 0; +} + + +static void dp_free(struct devpoll *dp) +{ + int ii; + struct list_head *lnk; + struct file *file; + + lock_kernel(); + for (ii = 0; ii <= dp->hmask; ii++) { + while ((lnk = list_first(&dp->hash[ii]))) { + struct dpitem *dpi = list_entry(lnk, struct dpitem, lnk); + + if (current->files && (file = fcheck(dpi->pfd.fd))) + file_notify_delcb(file, notify_proc); + list_del(lnk); + dpi_mem_free(dpi); + } + } + kfree(dp->hash); + if (dp->numpages > 0) { + dp_free_pages(dp->pages0, dp->numpages); + dp_free_pages(dp->pages1, dp->numpages); + } + unlock_kernel(); +} + + +static struct dpitem *dp_find(struct devpoll *dp, int fd) +{ + struct dpitem *dpi = NULL; + struct list_head *head = &dp->hash[fd & dp->hmask], *lnk; + unsigned long flags; + + read_lock_irqsave(&dp->lock, flags); + + list_for_each(lnk, head) { + dpi = list_entry(lnk, struct dpitem, lnk); + + if (dpi->pfd.fd == fd) break; + dpi = NULL; + } + + read_unlock_irqrestore(&dp->lock, flags); + DNPRINTK(3, (KERN_INFO "[%p] /dev/poll: dp_find(%d) -> %p\n", current, fd, dpi )); + + return dpi; +} + + +static int dp_hashresize(struct devpoll *dp) +{ + struct list_head *hash; + unsigned int hbits = dp->hbits + 1; + unsigned int hmask = (1 << hbits) - 1; + int ii, hentries = hmask + 1; + + DNPRINTK(3, (KERN_INFO "[%p] /dev/poll: dp_hashresize(%p) bits=%u\n", current, dp, hbits)); + + if (!(hash = (struct list_head *) kmalloc(hentries * sizeof(struct list_head), + GFP_KERNEL))) + return -ENOMEM; + + for (ii = 0; ii < hentries; ii++) + INIT_LIST_HEAD(&hash[ii]); + + for (ii = 0; ii <= dp->hmask; ii++) { + struct list_head *oldhead = &dp->hash[ii], *lnk; + + while ((lnk = list_first(oldhead))) { + struct dpitem *dpi = list_entry(lnk, struct dpitem, lnk); + + list_del(lnk); + list_add(lnk, &hash[dpi->pfd.fd & hmask]); + } + } + kfree(dp->hash); + + dp->hash = hash; + dp->hbits = hbits; + dp->hmask = hmask; + + return 0; +} + + +static int dp_insert(struct devpoll *dp, struct pollfd *pfd) +{ + struct dpitem *dpi; + struct file *file; + unsigned long flags = 0; + + if (atomic_read(&dp->hents) >= (dp->numpages * POLLFD_X_PAGE)) + return -E2BIG; + + if (!(file = fcheck(pfd->fd))) + return -EINVAL; + + if (!(dpi = dpi_mem_alloc())) + return -ENOMEM; + + INIT_LIST_HEAD(&dpi->lnk); + dpi->dp = dp; + dpi->pfd = *pfd; + dpi->index = -1; + dpi->ver = dp->ver - 1; + + write_lock_irqsave(&dp->lock, flags); + + list_add(&dpi->lnk, &dp->hash[pfd->fd & dp->hmask]); + atomic_inc(&dp->hents); + + if ((atomic_read(&dp->hents) >> dp->hbits) > RESIZE_LENGTH && + dp->hbits < MAX_HASH_BITS) + dp_hashresize(dp); + + write_unlock_irqrestore(&dp->lock, flags); + + file_notify_addcb(file, notify_proc, dpi); + + DNPRINTK(3, (KERN_INFO "[%p] /dev/poll: dp_insert(%p, %d)\n", current, dp, pfd ->fd)); + + return 0; +} + + +static int dp_remove(struct devpoll *dp, struct dpitem *dpi) +{ + int fd = dpi->pfd.fd; + struct file *file; + unsigned long flags = 0; + + write_lock_irqsave(&dp->lock, flags); + + list_del(&dpi->lnk); + atomic_dec(&dp->hents); + + write_unlock_irqrestore(&dp->lock, flags); + + if ((file = fcheck(fd))) + file_notify_delcb(file, notify_proc); + + dpi_mem_free(dpi); + + DNPRINTK(3, (KERN_INFO "[%p] /dev/poll: dp_remove(%p, %d)\n", current, dp, fd) ); + + return 0; +} + + +static void notify_proc(struct file *file, void *data, unsigned long *local, lo ng *event) +{ + struct dpitem *dpi = (struct dpitem *) data; + struct devpoll *dp = dpi->dp; + struct pollfd *pfd; + + DNPRINTK(3, (KERN_INFO "[%p] /dev/poll: notify(%p, %p, %ld, %ld) dp=%p\n", + current, file, data, event[0], event[1], dp)); + + write_lock(&dp->lock); + if (!(dpi->pfd.events & event[1])) + goto out; + + if (dpi->index < 0 || dpi->ver != dp->ver) { + if (dp->eventcnt >= (dp->numpages * POLLFD_X_PAGE)) + goto out; + dpi->index = dp->eventcnt++; + dpi->ver = dp->ver; + pfd = (struct pollfd *) (dp->pages[EVENT_PAGE_INDEX(dpi->index)] + + EVENT_PAGE_OFFSET(dpi->index)); + *pfd = dpi->pfd; + } else { + pfd = (struct pollfd *) (dp->pages[EVENT_PAGE_INDEX(dpi->index)] + + EVENT_PAGE_OFFSET(dpi->index)); + if (pfd->fd != dpi->pfd.fd) { + if (dp->eventcnt >= (dp->numpages * POLLFD_X_PAGE)) + goto out; + dpi->index = dp->eventcnt++; + pfd = (struct pollfd *) (dp->pages[EVENT_PAGE_INDEX(dpi->index)] + + EVENT_PAGE_OFFSET(dpi->index)); + *pfd = dpi->pfd; + } + } + + pfd->revents |= (pfd->events & event[1]); + + if (atomic_read(&dp->sleepers) && + (dp->eventcnt > dp->minevents || (jiffies - dp->jiffies) >= dp->minjiffies)) { + wake_up(&dp->wq); + } +out: + write_unlock(&dp->lock); +} + + +static int open_devpoll(struct inode *inode, struct file *file) +{ + int res; + struct devpoll *dp; + + if (!(dp = kmalloc(sizeof(struct devpoll), GFP_KERNEL))) + return -ENOMEM; + + memset(dp, 0, sizeof(*dp)); + if ((res = dp_init(dp))) { + kfree(dp); + return res; + } + + file->private_data = dp; + + MOD_INC_USE_COUNT; + + DNPRINTK(3, (KERN_INFO "[%p] /dev/poll: open() dp=%p\n", current, dp)); + return 0; +} + + +static int close_devpoll(struct inode *inode, struct file *file) +{ + struct devpoll *dp = file->private_data; + + dp_free(dp); + + kfree(dp); + + MOD_DEC_USE_COUNT; + + DNPRINTK(3, (KERN_INFO "[%p] /dev/poll: close() dp=%p\n", current, dp)); + return 0; +} + + +static int write_devpoll(struct file *file, const char *buffer, size_t count, + loff_t *ppos) +{ + int res, rcount; + struct devpoll *dp = file->private_data; + struct dpitem *dpi; + struct pollfd pfd; + + DNPRINTK(3, (KERN_INFO "[%p] /dev/poll: write(%p, %d)\n", current, dp, count)) ; + + if (count % sizeof(struct pollfd)) + return -EINVAL; + + if ((res = verify_area(VERIFY_READ, buffer, count))) + return res; + + rcount = 0; + + lock_kernel(); + + while (count > 0) { + __copy_from_user(&pfd, buffer, sizeof(pfd)); + + dpi = dp_find(dp, pfd.fd); + + if (pfd.fd >= current->files->max_fds || !current->files->fd[pfd.fd]) + pfd.events = POLLREMOVE; + if (pfd.events & POLLREMOVE) { + if (dpi) { + dp_remove(dp, dpi); + rcount += sizeof(pfd); + } + } + else if (dpi) { + dpi->pfd.events = pfd.events; + rcount += sizeof(pfd); + } + else { + pfd.revents = 0; + if (!dp_insert(dp, &pfd)) + rcount += sizeof(pfd); + } + + buffer += sizeof(pfd); + count -= sizeof(pfd); + } + + unlock_kernel(); + + return rcount; +} + + +static int dp_poll(struct devpoll *dp, void *arg) +{ + int res = 0; + long timeout; + unsigned long flags; + struct dvpoll dvp; + wait_queue_t wait; + + if (copy_from_user(&dvp, arg, sizeof(struct dvpoll))) + return -EFAULT; + + if (!atomic_read(&dp->mmapped)) + return -EINVAL; + + DNPRINTK(3, (KERN_INFO "[%p] /dev/poll: ioctl(%p, DP_POLL, %d)\n", current, dp , dvp.dp_timeout)); + + write_lock_irqsave(&dp->lock, flags); + + init_waitqueue_entry(&wait, current); + add_wait_queue(&dp->wq, &wait); + atomic_inc(&dp->sleepers); + timeout = dvp.dp_timeout * HZ; + for (;;) { + if (dp->eventcnt > 0 && (jiffies - dp->jiffies) >= dp->minjiffies) + break; + + if (!timeout || signal_pending(current)) + break; + + set_current_state(TASK_INTERRUPTIBLE); + + write_unlock_irqrestore(&dp->lock, flags); + timeout = schedule_timeout(timeout); + write_lock_irqsave(&dp->lock, flags); + } + atomic_dec(&dp->sleepers); + remove_wait_queue(&dp->wq, &wait); + + set_current_state(TASK_RUNNING); + + res = -EINTR; + if (dp->eventcnt > 0) { + res = dp->eventcnt; + dp->eventcnt = 0; + dp->jiffies = jiffies; + ++dp->ver; + if (dp->pages == dp->pages0) { + dp->pages = dp->pages1; + dvp.dp_resoff = 0; + } else { + dp->pages = dp->pages0; + dvp.dp_resoff = dp->numpages * PAGE_SIZE; + } + + copy_to_user(arg, &dvp, sizeof(struct dvpoll)); + } + + write_unlock_irqrestore(&dp->lock, flags); + + DNPRINTK(3, (KERN_INFO "[%p] /dev/poll: ioctl(%p, DP_POLL, %d) == %d\n", curre nt, dp, dvp.dp_timeout, res)); + return res; +} + + +static int ioctl_devpoll(struct inode *inode, struct file *file, + unsigned int cmd, unsigned long arg) +{ + int res, numpages; + struct devpoll *dp = file->private_data; + unsigned long flags; + struct dvtune dpt; + + switch (cmd) { + case DP_ALLOC: + if (atomic_read(&dp->mmapped)) + return -EBUSY; + + numpages = DP_FDS_PAGES(arg); + if (numpages > MAX_DEVPOLL_PAGES) + return -EINVAL; + + res = -EBUSY; + write_lock_irqsave(&dp->lock, flags); + if (dp->numpages == 0) { + if (!(res = dp_alloc_pages(dp->pages0, numpages))) { + if (!(res = dp_alloc_pages(dp->pages1, numpages))) { + dp->numpages = numpages; + dp->pages = dp->pages0; + res = 0; + } else { + dp_free_pages(dp->pages0, numpages); + } + } + } + write_unlock_irqrestore(&dp->lock, flags); + + DNPRINTK(3, (KERN_INFO "[%p] /dev/poll: ioctl(%p, DP_ALLOC, %lu) == %d\n", cu rrent, dp, arg, res)); + return res; + + case DP_FREE: + if (atomic_read(&dp->mmapped)) + return -EBUSY; + + res = -EINVAL; + write_lock_irqsave(&dp->lock, flags); + if (dp->numpages > 0) { + dp_free_pages(dp->pages0, dp->numpages); + dp_free_pages(dp->pages1, dp->numpages); + dp->numpages = 0; + dp->pages = NULL; + res = 0; + } + write_unlock_irqrestore(&dp->lock, flags); + + DNPRINTK(3, (KERN_INFO "[%p] /dev/poll: ioctl(%p, DP_FREE) == %d\n", current, dp, res)); + return res; + + case DP_POLL: + return dp_poll(dp, (void *) arg); + + case DP_TUNE: + if (copy_from_user(&dpt, arg, sizeof(struct dvtune))) + return -EFAULT; + + write_lock_irqsave(&dp->lock, flags); + dp->minevents = dpt.dp_minevents; + dp->minjiffies = (dpt.dp_msminwait * HZ) / 1000; + write_unlock_irqrestore(&dp->lock, flags); + return 0; + } + + return -EINVAL; +} + + +static void devpoll_mm_open(struct vm_area_struct * vma) +{ + struct file *file = vma->vm_file; + struct devpoll *dp = file->private_data; + + if (dp) atomic_inc(&dp->mmapped); + + DNPRINTK(3, (KERN_INFO "[%p] /dev/poll: mm_open(%p)\n", current, dp)); +} + + +static void devpoll_mm_close(struct vm_area_struct * vma) +{ + struct file *file = vma->vm_file; + struct devpoll *dp = file->private_data; + + if (dp) atomic_dec(&dp->mmapped); + + DNPRINTK(3, (KERN_INFO "[%p] /dev/poll: mm_close(%p)\n", current, dp)); +} + + +static int mmap_devpoll(struct file *file, struct vm_area_struct *vma) +{ + struct devpoll *dp = file->private_data; + unsigned long start, flags; + int ii, res; + int numpages; + size_t mapsize; + + DNPRINTK(3, (KERN_INFO "[%p] /dev/poll: mmap(%p, %lx, %lx)\n", + current, dp, vma->vm_start, vma->vm_pgoff << PAGE_SHIFT)); + + if ((vma->vm_pgoff << PAGE_SHIFT) != 0) + return -EINVAL; + + mapsize = PAGE_ALIGN(vma->vm_end - vma->vm_start); + numpages = mapsize >> PAGE_SHIFT; + + write_lock_irqsave(&dp->lock, flags); + + res = -EINVAL; + if (numpages != (2 * dp->numpages)) + goto out; + + start = vma->vm_start; + for (ii = 0; ii < dp->numpages; ii++) { + if (remap_page_range(start, __pa(dp->pages0[ii]), + PAGE_SIZE, vma->vm_page_prot)) + goto out; + start += PAGE_SIZE; + } + for (ii = 0; ii < dp->numpages; ii++) { + if (remap_page_range(start, __pa(dp->pages1[ii]), + PAGE_SIZE, vma->vm_page_prot)) + goto out; + start += PAGE_SIZE; + } + vma->vm_ops = &devpoll_mmap_ops; + atomic_set(&dp->mmapped, 1); + res = 0; +out: + write_unlock_irqrestore(&dp->lock, flags); + + DNPRINTK(3, (KERN_INFO "[%p] /dev/poll: mmap(%p, %lx, %lx) == %d\n", + current, dp, vma->vm_start, vma->vm_pgoff << PAGE_SHIFT, res)); + return res; +} + + +int __init devpoll_init(void) +{ + dpi_cache = kmem_cache_create("devpoll", + sizeof(struct dpitem), + __alignof__(struct dpitem), + DPI_SLAB_DEBUG, NULL, NULL); + if (!dpi_cache) { + printk(KERN_INFO "[%p] /dev/poll: driver install failed.\n", current); + return -ENOMEM; + } + + printk(KERN_INFO "[%p] /dev/poll: driver installed.\n", current); + + misc_register(&devpoll); + + return 0; +} + + +module_init(devpoll_init); + +#ifdef MODULE + +void cleanup_module(void) +{ + misc_deregister(&devpoll); + kmem_cache_destroy(dpi_cache); +} + +#endif + diff -NBbru linux-2.4.6.vanilla/fs/fcntl.c linux-2.4.6/fs/fcntl.c --- linux-2.4.6.vanilla/fs/fcntl.c Tue May 22 09:26:06 2001 +++ linux-2.4.6/fs/fcntl.c Wed Jul 4 15:38:38 2001 @@ -360,7 +360,7 @@ /* Table to convert sigio signal codes into poll band bitmaps */ -static long band_table[NSIGPOLL] = { +long band_table[NSIGPOLL] = { POLLIN | POLLRDNORM, /* POLL_IN */ POLLOUT | POLLWRNORM | POLLWRBAND, /* POLL_OUT */ POLLIN | POLLRDNORM | POLLMSG, /* POLL_MSG */ diff -NBbru linux-2.4.6.vanilla/fs/file.c linux-2.4.6/fs/file.c --- linux-2.4.6.vanilla/fs/file.c Fri Feb 9 11:29:44 2001 +++ linux-2.4.6/fs/file.c Mon Jul 2 17:12:56 2001 @@ -228,5 +228,84 @@ free_fdset(new_execset, nfds); write_lock(&files->file_lock); return error; +} + +void file_notify_event(struct file *filep, long *event) +{ + unsigned long flags; + struct list_head *lnk; + + fcblist_read_lock(filep, flags); + + list_for_each(lnk, &filep->f_cblist) { + struct fcb_struct *fcbp = list_entry(lnk, struct fcb_struct, lnk); + + fcbp->cbproc(filep, fcbp->data, fcbp->local, event); + } + + fcblist_read_unlock(filep, flags); +} + +int file_notify_addcb(struct file *filep, + void (*cbproc)(struct file *, void *, unsigned long *, long *), void *data) +{ + unsigned long flags; + struct fcb_struct *fcbp; + + if (!(fcbp = (struct fcb_struct *) kmalloc(sizeof(struct fcb_struct), GFP_KERN EL))) + return -ENOMEM; + + memset(fcbp, 0, sizeof(struct fcb_struct)); + fcbp->cbproc = cbproc; + fcbp->data = data; + + fcblist_write_lock(filep, flags); + list_add_tail(&fcbp->lnk, &filep->f_cblist); + fcblist_write_unlock(filep, flags); + + return 0; +} + +int file_notify_delcb(struct file *filep, + void (*cbproc)(struct file *, void *, unsigned long *, long *)) +{ + int error; + unsigned long flags; + struct list_head *lnk; + + fcblist_write_lock(filep, flags); + + error = -ENOENT; + list_for_each(lnk, &filep->f_cblist) { + struct fcb_struct *fcbp = list_entry(lnk, struct fcb_struct, lnk); + + if (fcbp->cbproc == cbproc) { + list_del(lnk); + kfree(fcbp); + error = 0; + break; + } + } + + fcblist_write_unlock(filep, flags); + + return error; +} + +void file_notify_cleanup(struct file *filep) +{ + unsigned long flags; + struct list_head *lnk; + + fcblist_write_lock(filep, flags); + + while ((lnk = list_first(&filep->f_cblist))) { + struct fcb_struct *fcbp = list_entry(lnk, struct fcb_struct, lnk); + + list_del(lnk); + kfree(fcbp); + } + + fcblist_write_unlock(filep, flags); } diff -NBbru linux-2.4.6.vanilla/fs/file_table.c linux-2.4.6/fs/file_table.c --- linux-2.4.6.vanilla/fs/file_table.c Wed Apr 18 11:49:12 2001 +++ linux-2.4.6/fs/file_table.c Mon Jul 2 16:27:29 2001 @@ -46,6 +46,8 @@ f->f_uid = current->fsuid; f->f_gid = current->fsgid; list_add(&f->f_list, &anon_list); + rwlock_init(&f->f_cblock); + INIT_LIST_HEAD(&f->f_cblist); file_list_unlock(); return f; } @@ -90,6 +92,8 @@ filp->f_uid = current->fsuid; filp->f_gid = current->fsgid; filp->f_op = dentry->d_inode->i_fop; + rwlock_init(&filp->f_cblock); + INIT_LIST_HEAD(&filp->f_cblist); if (filp->f_op->open) return filp->f_op->open(dentry->d_inode, filp); else @@ -103,6 +107,7 @@ struct inode * inode = dentry->d_inode; if (atomic_dec_and_test(&file->f_count)) { + file_notify_cleanup(file); locks_remove_flock(file); if (file->f_op && file->f_op->release) file->f_op->release(inode, file); diff -NBbru linux-2.4.6.vanilla/include/asm-i386/poll.h linux-2.4.6/include/asm- i386/poll.h --- linux-2.4.6.vanilla/include/asm-i386/poll.h Thu Jan 23 11:01:28 1997 +++ linux-2.4.6/include/asm-i386/poll.h Tue Jul 3 17:09:21 2001 @@ -15,6 +15,7 @@ #define POLLWRNORM 0x0100 #define POLLWRBAND 0x0200 #define POLLMSG 0x0400 +#define POLLREMOVE 0x1000 struct pollfd { int fd; diff -NBbru linux-2.4.6.vanilla/include/linux/devpoll.h linux-2.4.6/include/linu x/devpoll.h --- linux-2.4.6.vanilla/include/linux/devpoll.h Wed Dec 31 16:00:00 1969 +++ linux-2.4.6/include/linux/devpoll.h Sat Jul 7 15:49:42 2001 @@ -0,0 +1,52 @@ +/* + * + * /dev/poll support + * by Davide Libenzi + * + */ + +#ifndef _LINUX_DEVPOLL_H +#define _LINUX_DEVPOLL_H + + + + +#define DEVPOLL_MINOR 125 +#define POLLFD_X_PAGE (PAGE_SIZE / sizeof(struct pollfd)) +#define MAX_FDS_IN_DEVPOLL 32000 +#define MAX_DEVPOLL_PAGES (MAX_FDS_IN_DEVPOLL / POLLFD_X_PAGE) +#define EVENT_PAGE_INDEX(n) ((n) / POLLFD_X_PAGE) +#define EVENT_PAGE_REM(n) ((n) % POLLFD_X_PAGE) +#define EVENT_PAGE_OFFSET(n) (((n) % POLLFD_X_PAGE) * sizeof(struct pollfd)) +#define DP_FDS_PAGES(n) (((n) + POLLFD_X_PAGE - 1) / POLLFD_X_PAGE) +#define DP_MAP_SIZE(n) (DP_FDS_PAGES(n) * PAGE_SIZE * 2) + + +#define __MIN(a, b) (((a) < (b)) ? (a): (b)) +#define __MAX(a, b) (((a) > (b)) ? (a): (b)) + + + + + +struct dvpoll { + int dp_timeout; + unsigned long dp_resoff; +}; + +struct dvtune { + int dp_minevents; + unsigned long dp_msminwait; +}; + +#define DP_ALLOC _IOR('P', 1, int) +#define DP_POLL _IOWR('P', 2, struct dvpoll) +#define DP_FREE _IO('P', 3) +#define DP_ISPOLLED _IOWR('P', 4, struct pollfd) +#define DP_TUNE _IOWR('P', 5, struct dvtune) + + + + +#endif + diff -NBbru linux-2.4.6.vanilla/include/linux/file.h linux-2.4.6/include/linux/f ile.h --- linux-2.4.6.vanilla/include/linux/file.h Wed Aug 23 11:22:26 2000 +++ linux-2.4.6/include/linux/file.h Mon Jul 2 17:12:31 2001 @@ -96,5 +96,17 @@ } void put_files_struct(struct files_struct *fs); + + +void file_notify_event(struct file *filep, long *event); + +int file_notify_addcb(struct file *filep, + void (*cbproc)(struct file *, void *, unsigned long *, long *), void *data); + +int file_notify_delcb(struct file *filep, + void (*cbproc)(struct file *, void *, unsigned long *, long *)); + +void file_notify_cleanup(struct file *filep); + #endif /* __LINUX_FILE_H */ diff -NBbru linux-2.4.6.vanilla/include/linux/fs.h linux-2.4.6/include/linux/fs. h --- linux-2.4.6.vanilla/include/linux/fs.h Wed Jul 4 10:44:54 2001 +++ linux-2.4.6/include/linux/fs.h Mon Jul 9 14:17:05 2001 @@ -494,6 +494,26 @@ int signum; /* posix.1b rt signal to be delivered on IO */ }; +/* file callback notification events */ +#define ION_IN 1 +#define ION_OUT 2 +#define ION_HUP 3 +#define ION_ERR 4 + +#define FCB_LOCAL_SIZE 4 + +#define fcblist_read_lock(fp, fl) read_lock_irqsave(&(fp)->f_cblock, fl) +#define fcblist_read_unlock(fp, fl) read_unlock_irqrestore(&(fp)->f_cblock, fl ) +#define fcblist_write_lock(fp, fl) write_lock_irqsave(&(fp)->f_cblock, fl) +#define fcblist_write_unlock(fp, fl) write_unlock_irqrestore(&(fp)->f_cblock, f l) + +struct fcb_struct { + struct list_head lnk; + void (*cbproc)(struct file *, void *, unsigned long *, long *); + void *data; + unsigned long local[FCB_LOCAL_SIZE]; +}; + struct file { struct list_head f_list; struct dentry *f_dentry; @@ -512,6 +532,10 @@ /* needed for tty driver, and maybe others */ void *private_data; + + /* file callback list */ + rwlock_t f_cblock; + struct list_head f_cblist; }; extern spinlock_t files_lock; #define file_list_lock() spin_lock(&files_lock); diff -NBbru linux-2.4.6.vanilla/include/linux/list.h linux-2.4.6/include/linux/l ist.h --- linux-2.4.6.vanilla/include/linux/list.h Fri Feb 16 16:06:17 2001 +++ linux-2.4.6/include/linux/list.h Mon Jul 2 16:14:27 2001 @@ -148,6 +148,10 @@ */ #define list_for_each(pos, head) \ for (pos = (head)->next; pos != (head); pos = pos->next) + +#define list_first(head) (((head)->next != (head)) ? (head)->next: (struct list _head *) 0) + +#define list_last(head) (((head)->prev != (head)) ? (head)->prev: (struct list_ head *) 0) #endif /* __KERNEL__ || _LVM_H_INCLUDE */ diff -NBbru linux-2.4.6.vanilla/include/net/sock.h linux-2.4.6/include/net/sock. h --- linux-2.4.6.vanilla/include/net/sock.h Fri May 25 18:03:05 2001 +++ linux-2.4.6/include/net/sock.h Mon Jul 9 14:17:22 2001 @@ -105,6 +105,8 @@ #include #include +#include +#include /* The AF_UNIX specific socket options */ @@ -1230,8 +1232,17 @@ static inline void sk_wake_async(struct sock *sk, int how, int band) { - if (sk->socket && sk->socket->fasync_list) + if (sk->socket) { + if (sk->socket->file) { + extern long ion_band_table[]; + extern long band_table[]; + long event[] = { ion_band_table[band - POLL_IN], band_table[band - POLL_IN], -1 }; + + file_notify_event(sk->socket->file, event); + } + if (sk->socket->fasync_list) sock_wake_async(sk->socket, how, band); + } } #define SOCK_MIN_SNDBUF 2048 diff -NBbru linux-2.4.6.vanilla/net/core/sock.c linux-2.4.6/net/core/sock.c --- linux-2.4.6.vanilla/net/core/sock.c Wed Jul 4 10:44:56 2001 +++ linux-2.4.6/net/core/sock.c Wed Jul 4 10:46:21 2001 @@ -142,6 +142,16 @@ /* Maximal space eaten by iovec or ancilliary data plus some space */ int sysctl_optmem_max = sizeof(unsigned long)*(2*UIO_MAXIOV + 512); +/* Maps from band to file notification events ( used by sk_wake_async() ) */ +long ion_band_table[NSIGPOLL] = { + ION_IN, /* POLL_IN */ + ION_OUT, /* POLL_OUT */ + ION_IN, /* POLL_MSG */ + ION_ERR, /* POLL_ERR */ + 0, /* POLL_PRI */ + ION_HUP /* POLL_HUP */ +}; + static int sock_set_timeout(long *timeo_p, char *optval, int optlen) { struct timeval tv;