Re: Once again

Richard Gooch (rgooch@atnf.csiro.au)
Tue, 29 Jun 1999 12:38:50 +1000


Dale Amon writes:
> On Tue, 29 Jun 1999, Richard Gooch wrote:
>
> > patch, you can be informed when an inode is written to since the last
> > poll(). Doesn't that take care of everything?
> >
>
> Ah, you leave me one of two choices. Either go read the code or
> ask a dumb question :-)

;-)

> With respect to what entity does the "update since last poll" occur?
> ie if there are multiple poll()'ers, does each have their own
> private view or does each reset the time since last poll?

Each has their own private view. Upon notify, each poller has it's
state updated. The state for that poller is cleared when poll() reads
it. Code appended.

Said another way: if process A is blocking in poll(), it will be woken
up and will read/clear the state. If later process B calls poll(), it
will read/clear its state (except the first time, when the state is
0).

Regards,

Richard....

diff -urN linux-2.3.5/fs/Makefile linux/fs/Makefile
--- linux-2.3.5/fs/Makefile Wed Jun 23 23:54:54 1999
+++ linux/fs/Makefile Mon Jun 28 19:02:17 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-2.3.5/fs/ext2/dir.c linux/fs/ext2/dir.c
--- linux-2.3.5/fs/ext2/dir.c Sat Apr 24 14:20:37 1999
+++ linux/fs/ext2/dir.c Mon Jun 28 19:02:19 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-2.3.5/fs/ext2/file.c linux/fs/ext2/file.c
--- linux-2.3.5/fs/ext2/file.c Tue Dec 22 10:22:54 1998
+++ linux/fs/ext2/file.c Mon Jun 28 22:09:51 1999
@@ -66,7 +66,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
@@ -320,6 +320,7 @@
{
if (filp->f_mode & FMODE_WRITE)
ext2_discard_prealloc (inode);
+ vfs_release (inode, filp);
return 0;
}

diff -urN linux-2.3.5/fs/namei.c linux/fs/namei.c
--- linux-2.3.5/fs/namei.c Sun May 16 16:43:05 1999
+++ linux/fs/namei.c Mon Jun 28 19:02:19 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>
@@ -647,6 +648,8 @@

DQUOT_INIT(dir);
error = dir->i_op->create(dir, dentry, mode);
+ if (!error)
+ vfs_poll_notify (dir, POLLWRINODE);
exit_lock:
return error;
}
@@ -825,6 +828,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)
@@ -917,6 +922,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);
@@ -1012,6 +1019,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:
@@ -1066,6 +1075,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);
@@ -1116,6 +1127,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);
@@ -1202,6 +1215,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);
@@ -1374,7 +1389,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-2.3.5/fs/read_write.c linux/fs/read_write.c
--- linux-2.3.5/fs/read_write.c Mon Dec 28 05:52:09 1998
+++ linux/fs/read_write.c Mon Jun 28 23:53:05 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>

@@ -169,6 +170,8 @@
down(&inode->i_sem);
ret = write(file, buf, count, &file->f_pos);
up(&inode->i_sem);
+ if (ret > 0)
+ vfs_poll_notify (file->f_dentry->d_inode, POLLWRINODE);
out:
fput(file);
bad_file:
@@ -307,6 +310,8 @@
down(&file->f_dentry->d_inode->i_sem);
ret = do_readv_writev(VERIFY_READ, file, vector, count);
up(&file->f_dentry->d_inode->i_sem);
+ if (ret > 0)
+ vfs_poll_notify (file->f_dentry->d_inode, POLLWRINODE);
}
fput(file);

@@ -379,6 +384,8 @@
down(&file->f_dentry->d_inode->i_sem);
ret = write(file, buf, count, &pos);
up(&file->f_dentry->d_inode->i_sem);
+ if (ret > 0)
+ vfs_poll_notify (file->f_dentry->d_inode, POLLWRINODE);

out:
fput(file);
diff -urN linux-2.3.5/fs/vfs_poll.c linux/fs/vfs_poll.c
--- linux-2.3.5/fs/vfs_poll.c Thu Jan 1 10:00:00 1970
+++ linux/fs/vfs_poll.c Mon Jun 28 21:58:01 1999
@@ -0,0 +1,54 @@
+#include <linux/fs.h>
+#include <linux/malloc.h>
+#include <linux/poll.h>
+
+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;
+ }
+ file->private_data = entry;
+ memset (entry, 0, sizeof *entry);
+ init_waitqueue_head (&entry->wait);
+ 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;
+} /* 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-2.3.5/include/linux/fs.h linux/include/linux/fs.h
--- linux-2.3.5/include/linux/fs.h Fri Jun 25 11:00:33 1999
+++ linux/include/linux/fs.h Mon Jun 28 19:04:25 1999
@@ -336,6 +336,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;
@@ -365,6 +372,7 @@
struct file_lock *i_flock;
struct vm_area_struct *i_mmap;
struct page *i_pages;
+ struct vfs_poll_info *i_vfs_poll;
struct dquot *i_dquot[MAXQUOTAS];

unsigned long i_state;
@@ -400,6 +408,17 @@
void *generic_ip;
} 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
diff -urN linux-2.3.5/include/linux/poll.h linux/include/linux/poll.h
--- linux-2.3.5/include/linux/poll.h Fri Jun 25 11:00:35 1999
+++ linux/include/linux/poll.h Mon Jun 28 19:04:27 1999
@@ -3,6 +3,9 @@

#include <asm/poll.h>

+/* Linux-specific poll events: valid for all architectures */
+#define POLLWRINODE 0x8000
+
#ifdef __KERNEL__

#include <linux/wait.h>

-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.rutgers.edu
Please read the FAQ at http://www.tux.org/lkml/