[EMAIL PROTECTED] writes:
> On Sun, May 21, 2000 at 04:27:29PM +0000, Ton Hospel wrote:
> > A poll() notification mechanism should be at least as useful for e.g.
> > GUI's who generally prefer to have synchronous notification.
> 
> Alan mentioned there were fundamental problems with this, so I
> didn't even bother investigating.

I did this last year, so I claim it's possible ;-)
I've appended my patch from back then.

                                Regards,

                                        Richard....
Permanent: [EMAIL PROTECTED]
Current:   [EMAIL PROTECTED]
===============================================================================
diff -urN linux.old/fs/Makefile linux/fs/Makefile
--- linux.old/fs/Makefile       Tue Jul 13 16:03:52 1999
+++ linux/fs/Makefile   Wed Jul 14 08:20:35 1999
@@ -13,7 +13,7 @@
 O_OBJS    = open.o read_write.o devices.o file_table.o buffer.o \
                super.o  block_dev.o stat.o exec.o pipe.o namei.o fcntl.o \
                ioctl.o readdir.o select.o fifo.o locks.o filesystems.o \
-               dcache.o inode.o attr.o bad_inode.o $(BINFMTS) 
+               dcache.o inode.o attr.o bad_inode.o vfs_poll.o $(BINFMTS) 
 
 MOD_LIST_NAME := FS_MODULES
 ALL_SUB_DIRS = coda minix ext2 fat msdos vfat proc isofs nfs umsdos ntfs \
diff -urN linux.old/fs/attr.c linux/fs/attr.c
--- linux.old/fs/attr.c Sat Nov 14 05:07:26 1998
+++ linux/fs/attr.c     Wed Jul 14 08:20:35 1999
@@ -8,6 +8,7 @@
 #include <linux/sched.h>
 #include <linux/mm.h>
 #include <linux/string.h>
+#include <linux/poll.h>
 
 /* Taken over from the old code... */
 
@@ -99,5 +100,10 @@
                if (!error)
                        inode_setattr(inode, attr);
        }
+       if (!error)
+               if (ia_valid & ATTR_SIZE)
+                       vfs_poll_notify (inode, POLLWRINODE);
+               if (ia_valid & ~ATTR_SIZE)
+                       vfs_poll_notify (inode, POLLCHANGEDINODE);
        return error;
 }
diff -urN linux.old/fs/ext2/dir.c linux/fs/ext2/dir.c
--- linux.old/fs/ext2/dir.c     Sun Jun 27 05:04:39 1999
+++ linux/fs/ext2/dir.c Wed Jul 14 08:20:35 1999
@@ -39,12 +39,12 @@
        ext2_dir_read,          /* read */
        NULL,                   /* write - bad */
        ext2_readdir,           /* readdir */
-       NULL,                   /* poll - default */
+       vfs_poll,               /* poll - use VFS */
        ext2_ioctl,             /* ioctl */
        NULL,                   /* mmap */
        NULL,                   /* no special open code */
        NULL,                   /* flush */
-       NULL,                   /* no special release code */
+       vfs_release,            /* for vfs_poll() */
        ext2_sync_file,         /* fsync */
        NULL,                   /* fasync */
        NULL,                   /* check_media_change */
diff -urN linux.old/fs/ext2/file.c linux/fs/ext2/file.c
--- linux.old/fs/ext2/file.c    Sun Jun 27 05:04:39 1999
+++ linux/fs/ext2/file.c        Wed Jul 14 08:20:35 1999
@@ -133,6 +133,7 @@
 {
        if (filp->f_mode & FMODE_WRITE)
                ext2_discard_prealloc (inode);
+       vfs_release (inode, filp);
        return 0;
 }
 
@@ -158,7 +159,7 @@
        generic_file_read,      /* read */
        ext2_file_write,        /* write */
        NULL,                   /* readdir - bad */
-       NULL,                   /* poll - default */
+       vfs_poll,               /* poll - use VFS */
        ext2_ioctl,             /* ioctl */
        generic_file_mmap,      /* mmap */
 #if BITS_PER_LONG == 64        
diff -urN linux.old/fs/fcntl.c linux/fs/fcntl.c
--- linux.old/fs/fcntl.c        Tue Jul 13 12:41:22 1999
+++ linux/fs/fcntl.c    Wed Jul 14 08:20:35 1999
@@ -94,6 +94,13 @@
               if (arg & O_NDELAY)
                   arg |= O_NONBLOCK;
 
+       if (current->fsuid == inode->i_uid || capable(CAP_FOWNER)) {
+               if (arg & O_FORCEMANDLCK)
+                       inode->i_flags |= I_MANDLOCK;
+               else
+                       inode->i_flags &= ~I_MANDLOCK;
+       }
+
        filp->f_flags = (arg & SETFL_MASK) | (filp->f_flags & ~SETFL_MASK);
        return 0;
 }
diff -urN linux.old/fs/locks.c linux/fs/locks.c
--- linux.old/fs/locks.c        Tue Jul 13 12:41:22 1999
+++ linux/fs/locks.c    Wed Jul 14 08:36:13 1999
@@ -108,6 +108,7 @@
 #include <linux/malloc.h>
 #include <linux/file.h>
 #include <linux/smp_lock.h>
+#include <linux/poll.h>
 
 #include <asm/uaccess.h>
 
@@ -405,8 +406,7 @@
        /* Don't allow mandatory locks on files that may be memory mapped
         * and shared.
         */
-       if (IS_MANDLOCK(inode) &&
-           (inode->i_mode & (S_ISGID | S_IXGRP)) == S_ISGID) {
+       if (MANDATORY_LOCK(inode)) {
                struct vm_area_struct *vma;
                spin_lock(&inode->i_shared_lock);
                for(vma = inode->i_mmap;vma;vma = vma->vm_next_share) {
@@ -618,6 +618,7 @@
                        if (posix_locks_deadlock(&tfl, fl))
                                break;
 
+                       vfs_poll_notify (inode, POLLLOCKSLEEP);
                        locks_insert_block(fl, &tfl);
                        interruptible_sleep_on(&tfl.fl_wait);
                        locks_delete_block(fl, &tfl);
@@ -886,6 +887,7 @@
                error = -EAGAIN;
                if (!wait)
                        goto out;
+               vfs_poll_notify (inode, POLLLOCKSLEEP);
                locks_insert_block(fl, new_fl);
                interruptible_sleep_on(&new_fl->fl_wait);
                locks_delete_block(fl, new_fl);
@@ -950,6 +952,7 @@
                        error = -ERESTARTSYS;
                        if (signal_pending(current))
                                goto out;
+                       vfs_poll_notify (inode, POLLLOCKSLEEP);
                        locks_insert_block(fl, caller);
                        interruptible_sleep_on(&caller->fl_wait);
                        locks_delete_block(fl, caller);
@@ -1184,9 +1187,7 @@
        if (fl->fl_flags & FL_POSIX) {
                p += sprintf(p, "%6s %s ",
                             (fl->fl_flags & FL_ACCESS) ? "ACCESS" : "POSIX ",
-                            (IS_MANDLOCK(inode) &&
-                             (inode->i_mode & (S_IXGRP | S_ISGID)) == S_ISGID) ?
-                            "MANDATORY" : "ADVISORY ");
+                            MANDATORY_LOCK(inode) ? "MANDATORY" : "ADVISORY ");
        }
        else {
                p += sprintf(p, "FLOCK  ADVISORY  ");
diff -urN linux.old/fs/namei.c linux/fs/namei.c
--- linux.old/fs/namei.c        Tue Jul 13 12:41:22 1999
+++ linux/fs/namei.c    Wed Jul 14 08:20:35 1999
@@ -16,6 +16,7 @@
 #include <linux/proc_fs.h>
 #include <linux/smp_lock.h>
 #include <linux/quotaops.h>
+#include <linux/poll.h>
 
 #include <asm/uaccess.h>
 #include <asm/unaligned.h>
@@ -651,6 +652,8 @@
 
        DQUOT_INIT(dir);
        error = dir->i_op->create(dir, dentry, mode);
+       if (!error)
+               vfs_poll_notify (dir, POLLWRINODE);
 exit_lock:
        return error;
 }
@@ -829,6 +832,8 @@
 
        DQUOT_INIT(dir->d_inode);
        error = dir->d_inode->i_op->mknod(dir->d_inode, dentry, mode, dev);
+       if (!error)
+               vfs_poll_notify (dir->d_inode, POLLWRINODE);
 exit_lock:
        retval = ERR_PTR(error);
        if (!error)
@@ -921,6 +926,8 @@
        DQUOT_INIT(dir->d_inode);
        mode &= (S_IRWXUGO|S_ISVTX) & ~current->fs->umask;
        error = dir->d_inode->i_op->mkdir(dir->d_inode, dentry, mode);
+       if (!error)
+               vfs_poll_notify (dir->d_inode, POLLWRINODE);
 
 exit_lock:
        unlock_dir(dir);
@@ -1016,6 +1023,8 @@
        error = -ENOENT;
        if (check_parent(dir, dentry))
                error = vfs_rmdir(dir->d_inode, dentry);
+       if (!error)
+               vfs_poll_notify (dir->d_inode, POLLWRINODE);
 
        double_unlock(dentry, dir);
 exit_dput:
@@ -1070,6 +1079,8 @@
        error = -ENOENT;
        if (check_parent(dir, dentry))
                error = vfs_unlink(dir->d_inode, dentry);
+       if (!error)
+               vfs_poll_notify (dir->d_inode, POLLWRINODE);
 
         unlock_dir(dir);
        dput(dentry);
@@ -1120,6 +1131,8 @@
 
        DQUOT_INIT(dir->d_inode);
        error = dir->d_inode->i_op->symlink(dir->d_inode, dentry, oldname);
+       if (!error)
+               vfs_poll_notify (dir->d_inode, POLLWRINODE);
 
 exit_lock:
        unlock_dir(dir);
@@ -1206,6 +1219,8 @@
 
        DQUOT_INIT(dir->d_inode);
        error = dir->d_inode->i_op->link(old_dentry, dir->d_inode, new_dentry);
+       if (!error)
+               vfs_poll_notify (dir->d_inode, POLLWRINODE);
 
 exit_lock:
        unlock_dir(dir);
@@ -1378,7 +1393,11 @@
        if (check_parent(old_dir, old_dentry) && check_parent(new_dir, new_dentry))
                error = vfs_rename(old_dir->d_inode, old_dentry,
                                   new_dir->d_inode, new_dentry);
-
+       if (!error) {
+               vfs_poll_notify (old_dir->d_inode, POLLWRINODE);
+               vfs_poll_notify (new_dir->d_inode, POLLWRINODE);
+       }
+       
        double_unlock(new_dir, old_dir);
        dput(new_dentry);
 exit_old:
diff -urN linux.old/fs/read_write.c linux/fs/read_write.c
--- linux.old/fs/read_write.c   Tue Jun 29 06:31:07 1999
+++ linux/fs/read_write.c       Wed Jul 14 08:20:35 1999
@@ -10,6 +10,7 @@
 #include <linux/file.h>
 #include <linux/uio.h>
 #include <linux/smp_lock.h>
+#include <linux/poll.h>
 
 #include <asm/uaccess.h>
 
@@ -156,6 +157,8 @@
                        }
                }
                fput(file);
+               if (ret > 0)
+                       vfs_poll_notify (file->f_dentry->d_inode, POLLWRINODE);
        }
        return ret;
 }
@@ -291,7 +294,8 @@
                ret = do_readv_writev(VERIFY_READ, file, vector, count);
        }
        fput(file);
-
+       if (ret > 0)
+               vfs_poll_notify (file->f_dentry->d_inode, POLLWRINODE);
 bad_file:
        unlock_kernel();
        return ret;
@@ -361,6 +365,8 @@
        ret = write(file, buf, count, &pos);
 out:
        fput(file);
+       if (ret > 0)
+               vfs_poll_notify (file->f_dentry->d_inode, POLLWRINODE);
 bad_file:
        unlock_kernel();
        return ret;
diff -urN linux.old/fs/vfs_poll.c linux/fs/vfs_poll.c
--- linux.old/fs/vfs_poll.c     Thu Jan  1 10:00:00 1970
+++ linux/fs/vfs_poll.c Wed Jul 14 08:20:35 1999
@@ -0,0 +1,78 @@
+/*  VFS poll() interface: event notification for filesystem objects.
+
+    Copyright (C) 1999  Richard Gooch
+
+    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., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+    Richard Gooch may be reached by email at  [EMAIL PROTECTED]
+    The postal address is:
+      Richard Gooch, c/o ATNF, P. O. Box 76, Epping, N.S.W., 2121, Australia.
+*/
+#include <linux/fs.h>
+#include <linux/malloc.h>
+#include <linux/poll.h>
+
+#define DEFAULT_POLLMASK (POLLIN | POLLOUT | POLLRDNORM | POLLWRNORM)
+
+unsigned int vfs_poll (struct file *file, struct poll_table_struct *wait)
+{
+    unsigned int mask;
+    struct vfs_poll_info *entry = file->private_data;
+
+    if (!entry)
+    {
+       struct inode *inode = file->f_dentry->d_inode;
+
+       entry = kmalloc (sizeof *entry, GFP_KERNEL);
+       if (!entry)
+       {
+           printk ("vfs_poll(): could not allocate\n");
+           return 0;
+       }
+       memset (entry, 0, sizeof *entry);
+       init_waitqueue_head (&entry->wait);
+       file->private_data = entry;
+       entry->next = inode->i_vfs_poll;
+       if (inode->i_vfs_poll) inode->i_vfs_poll->prev = entry;
+       inode->i_vfs_poll = entry;
+    }
+    poll_wait (file, &entry->wait, wait);
+    mask = entry->events;
+    entry->events = 0;
+    return mask | DEFAULT_POLLMASK;
+}   /*  End Function vfs_poll  */
+
+int vfs_release (struct inode *inode, struct file *file)
+{
+    struct vfs_poll_info *entry = file->private_data;
+
+    if (!entry) return 0;
+    if (entry->prev) entry->prev->next = entry->next;
+    else inode->i_vfs_poll = entry->next;
+    if (entry->next) entry->next->prev = entry->prev;
+    kfree (entry);
+    return 0;
+}   /*  End Function vfs_release  */
+
+void __vfs_poll_notify (struct inode *inode, unsigned int events)
+{
+    struct vfs_poll_info *curr;
+
+    for (curr = inode->i_vfs_poll; curr; curr = curr->next)
+    {
+       curr->events |= events;
+       wake_up_interruptible (&curr->wait);
+    }
+}   /*  End Function __vfs_notify  */
diff -urN linux.old/include/asm-i386/fcntl.h linux/include/asm-i386/fcntl.h
--- linux.old/include/asm-i386/fcntl.h  Thu Oct 22 03:02:48 1998
+++ linux/include/asm-i386/fcntl.h      Wed Jul 14 08:20:35 1999
@@ -20,6 +20,7 @@
 #define O_LARGEFILE    0100000
 #define O_DIRECTORY    0200000 /* must be a directory */
 #define O_NOFOLLOW     0400000 /* don't follow links */
+#define O_FORCEMANDLCK 01000000 /* force mandatory locks for this inode */
 
 #define F_DUPFD                0       /* dup */
 #define F_GETFD                1       /* get f_flags */
diff -urN linux.old/include/linux/fs.h linux/include/linux/fs.h
--- linux.old/include/linux/fs.h        Tue Jul 13 16:03:54 1999
+++ linux/include/linux/fs.h    Wed Jul 14 08:39:48 1999
@@ -95,6 +95,7 @@
 #define S_IMMUTABLE    512     /* Immutable file */
 #define MS_NOATIME     1024    /* Do not update access times. */
 #define MS_NODIRATIME  2048    /* Do not update directory access times */
+#define I_MANDLOCK      0x1000  /* Force locks to be mandatory for this inode*/
 
 #define MS_ODD_RENAME  32768   /* Temporary stuff; will go away as soon
                                  * as nfs_rename() will be cleaned up
@@ -318,6 +319,13 @@
 #include <linux/quota.h>
 #include <linux/mount.h>
 
+struct vfs_poll_info {
+       unsigned short events;
+       wait_queue_head_t wait;
+       struct vfs_poll_info *prev;
+       struct vfs_poll_info *next;
+};
+
 struct inode {
        struct list_head        i_hash;
        struct list_head        i_list;
@@ -347,6 +355,7 @@
        struct vm_area_struct   *i_mmap;
        struct page             *i_pages;
        spinlock_t              i_shared_lock;
+       struct vfs_poll_info    *i_vfs_poll;
        struct dquot            *i_dquot[MAXQUOTAS];
        struct pipe_inode_info  *i_pipe;
 
@@ -382,6 +391,17 @@
        } u;
 };
 
+extern unsigned int vfs_poll (struct file *, struct poll_table_struct *);
+extern int vfs_release (struct inode *, struct file *);
+extern void __vfs_poll_notify (struct inode *inode, unsigned int events);
+
+static inline void vfs_poll_notify (struct inode *inode, unsigned int events)
+{
+       if (!inode->i_vfs_poll)
+               return;
+       __vfs_poll_notify (inode, events);
+}      
+
 /* Inode state bits.. */
 #define I_DIRTY                1
 #define I_LOCK         2
@@ -681,7 +701,8 @@
  * but no group execute bit -  an otherwise meaningless combination.
  */
 #define MANDATORY_LOCK(inode) \
-       (IS_MANDLOCK(inode) && ((inode)->i_mode & (S_ISGID | S_IXGRP)) == S_ISGID)
+       (((inode)->i_flags & I_MANDLOCK) || \
+        (IS_MANDLOCK(inode) && ((inode)->i_mode & (S_ISGID | S_IXGRP)) == S_ISGID))
 
 static inline int locks_verify_locked(struct inode *inode)
 {
diff -urN linux.old/include/linux/poll.h linux/include/linux/poll.h
--- linux.old/include/linux/poll.h      Thu Jul  1 05:42:49 1999
+++ linux/include/linux/poll.h  Wed Jul 14 08:20:36 1999
@@ -3,6 +3,11 @@
 
 #include <asm/poll.h>
 
+/*  Linux-specific poll events: valid for all architectures  */
+#define POLLLOCKSLEEP       0x2000  /*  Someone went to sleep on lock  */
+#define POLLCHANGEDINODE    0x4000  /*  Inode attributes were changed  */
+#define POLLWRINODE         0x8000  /*  Inode was written to           */
+
 #ifdef __KERNEL__
 
 #include <linux/wait.h>

Reply via email to