[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>