diff options
author | Tejun Heo <tj@kernel.org> | 2008-11-26 06:03:55 -0500 |
---|---|---|
committer | Miklos Szeredi <miklos@szeredi.hu> | 2008-11-26 06:03:55 -0500 |
commit | 95668a69a4bb862063c4d28a746e55107dee7b98 (patch) | |
tree | 0679e0f43274648bad70e694a9efb8bcfed55adc /fs/fuse/file.c | |
parent | 8599396b5062bf6bd2a0b433503849e2322df1c2 (diff) |
fuse: implement poll support
Implement poll support. Polled files are indexed using kh in a RB
tree rooted at fuse_conn->polled_files.
Client should send FUSE_NOTIFY_POLL notification once after processing
FUSE_POLL which has FUSE_POLL_SCHEDULE_NOTIFY set. Sending
notification unconditionally after the latest poll or everytime file
content might have changed is inefficient but won't cause malfunction.
fuse_file_poll() can sleep and requires patches from the following
thread which allows f_op->poll() to sleep.
http://thread.gmane.org/gmane.linux.kernel/726176
Signed-off-by: Tejun Heo <tj@kernel.org>
Signed-off-by: Miklos Szeredi <mszeredi@suse.cz>
Diffstat (limited to 'fs/fuse/file.c')
-rw-r--r-- | fs/fuse/file.c | 132 |
1 files changed, 132 insertions, 0 deletions
diff --git a/fs/fuse/file.c b/fs/fuse/file.c index a28ced678d38..b3a944e4bb9c 100644 --- a/fs/fuse/file.c +++ b/fs/fuse/file.c | |||
@@ -62,6 +62,8 @@ struct fuse_file *fuse_file_alloc(struct fuse_conn *fc) | |||
62 | ff->kh = ++fc->khctr; | 62 | ff->kh = ++fc->khctr; |
63 | spin_unlock(&fc->lock); | 63 | spin_unlock(&fc->lock); |
64 | } | 64 | } |
65 | RB_CLEAR_NODE(&ff->polled_node); | ||
66 | init_waitqueue_head(&ff->poll_wait); | ||
65 | } | 67 | } |
66 | return ff; | 68 | return ff; |
67 | } | 69 | } |
@@ -170,7 +172,11 @@ int fuse_release_common(struct inode *inode, struct file *file, int isdir) | |||
170 | 172 | ||
171 | spin_lock(&fc->lock); | 173 | spin_lock(&fc->lock); |
172 | list_del(&ff->write_entry); | 174 | list_del(&ff->write_entry); |
175 | if (!RB_EMPTY_NODE(&ff->polled_node)) | ||
176 | rb_erase(&ff->polled_node, &fc->polled_files); | ||
173 | spin_unlock(&fc->lock); | 177 | spin_unlock(&fc->lock); |
178 | |||
179 | wake_up_interruptible_sync(&ff->poll_wait); | ||
174 | /* | 180 | /* |
175 | * Normally this will send the RELEASE request, | 181 | * Normally this will send the RELEASE request, |
176 | * however if some asynchronous READ or WRITE requests | 182 | * however if some asynchronous READ or WRITE requests |
@@ -1749,6 +1755,130 @@ static long fuse_file_compat_ioctl(struct file *file, unsigned int cmd, | |||
1749 | return fuse_file_do_ioctl(file, cmd, arg, FUSE_IOCTL_COMPAT); | 1755 | return fuse_file_do_ioctl(file, cmd, arg, FUSE_IOCTL_COMPAT); |
1750 | } | 1756 | } |
1751 | 1757 | ||
1758 | /* | ||
1759 | * All files which have been polled are linked to RB tree | ||
1760 | * fuse_conn->polled_files which is indexed by kh. Walk the tree and | ||
1761 | * find the matching one. | ||
1762 | */ | ||
1763 | static struct rb_node **fuse_find_polled_node(struct fuse_conn *fc, u64 kh, | ||
1764 | struct rb_node **parent_out) | ||
1765 | { | ||
1766 | struct rb_node **link = &fc->polled_files.rb_node; | ||
1767 | struct rb_node *last = NULL; | ||
1768 | |||
1769 | while (*link) { | ||
1770 | struct fuse_file *ff; | ||
1771 | |||
1772 | last = *link; | ||
1773 | ff = rb_entry(last, struct fuse_file, polled_node); | ||
1774 | |||
1775 | if (kh < ff->kh) | ||
1776 | link = &last->rb_left; | ||
1777 | else if (kh > ff->kh) | ||
1778 | link = &last->rb_right; | ||
1779 | else | ||
1780 | return link; | ||
1781 | } | ||
1782 | |||
1783 | if (parent_out) | ||
1784 | *parent_out = last; | ||
1785 | return link; | ||
1786 | } | ||
1787 | |||
1788 | /* | ||
1789 | * The file is about to be polled. Make sure it's on the polled_files | ||
1790 | * RB tree. Note that files once added to the polled_files tree are | ||
1791 | * not removed before the file is released. This is because a file | ||
1792 | * polled once is likely to be polled again. | ||
1793 | */ | ||
1794 | static void fuse_register_polled_file(struct fuse_conn *fc, | ||
1795 | struct fuse_file *ff) | ||
1796 | { | ||
1797 | spin_lock(&fc->lock); | ||
1798 | if (RB_EMPTY_NODE(&ff->polled_node)) { | ||
1799 | struct rb_node **link, *parent; | ||
1800 | |||
1801 | link = fuse_find_polled_node(fc, ff->kh, &parent); | ||
1802 | BUG_ON(*link); | ||
1803 | rb_link_node(&ff->polled_node, parent, link); | ||
1804 | rb_insert_color(&ff->polled_node, &fc->polled_files); | ||
1805 | } | ||
1806 | spin_unlock(&fc->lock); | ||
1807 | } | ||
1808 | |||
1809 | static unsigned fuse_file_poll(struct file *file, poll_table *wait) | ||
1810 | { | ||
1811 | struct inode *inode = file->f_dentry->d_inode; | ||
1812 | struct fuse_file *ff = file->private_data; | ||
1813 | struct fuse_conn *fc = get_fuse_conn(inode); | ||
1814 | struct fuse_poll_in inarg = { .fh = ff->fh, .kh = ff->kh }; | ||
1815 | struct fuse_poll_out outarg; | ||
1816 | struct fuse_req *req; | ||
1817 | int err; | ||
1818 | |||
1819 | if (fc->no_poll) | ||
1820 | return DEFAULT_POLLMASK; | ||
1821 | |||
1822 | poll_wait(file, &ff->poll_wait, wait); | ||
1823 | |||
1824 | /* | ||
1825 | * Ask for notification iff there's someone waiting for it. | ||
1826 | * The client may ignore the flag and always notify. | ||
1827 | */ | ||
1828 | if (waitqueue_active(&ff->poll_wait)) { | ||
1829 | inarg.flags |= FUSE_POLL_SCHEDULE_NOTIFY; | ||
1830 | fuse_register_polled_file(fc, ff); | ||
1831 | } | ||
1832 | |||
1833 | req = fuse_get_req(fc); | ||
1834 | if (IS_ERR(req)) | ||
1835 | return PTR_ERR(req); | ||
1836 | |||
1837 | req->in.h.opcode = FUSE_POLL; | ||
1838 | req->in.h.nodeid = get_node_id(inode); | ||
1839 | req->in.numargs = 1; | ||
1840 | req->in.args[0].size = sizeof(inarg); | ||
1841 | req->in.args[0].value = &inarg; | ||
1842 | req->out.numargs = 1; | ||
1843 | req->out.args[0].size = sizeof(outarg); | ||
1844 | req->out.args[0].value = &outarg; | ||
1845 | request_send(fc, req); | ||
1846 | err = req->out.h.error; | ||
1847 | fuse_put_request(fc, req); | ||
1848 | |||
1849 | if (!err) | ||
1850 | return outarg.revents; | ||
1851 | if (err == -ENOSYS) { | ||
1852 | fc->no_poll = 1; | ||
1853 | return DEFAULT_POLLMASK; | ||
1854 | } | ||
1855 | return POLLERR; | ||
1856 | } | ||
1857 | |||
1858 | /* | ||
1859 | * This is called from fuse_handle_notify() on FUSE_NOTIFY_POLL and | ||
1860 | * wakes up the poll waiters. | ||
1861 | */ | ||
1862 | int fuse_notify_poll_wakeup(struct fuse_conn *fc, | ||
1863 | struct fuse_notify_poll_wakeup_out *outarg) | ||
1864 | { | ||
1865 | u64 kh = outarg->kh; | ||
1866 | struct rb_node **link; | ||
1867 | |||
1868 | spin_lock(&fc->lock); | ||
1869 | |||
1870 | link = fuse_find_polled_node(fc, kh, NULL); | ||
1871 | if (*link) { | ||
1872 | struct fuse_file *ff; | ||
1873 | |||
1874 | ff = rb_entry(*link, struct fuse_file, polled_node); | ||
1875 | wake_up_interruptible_sync(&ff->poll_wait); | ||
1876 | } | ||
1877 | |||
1878 | spin_unlock(&fc->lock); | ||
1879 | return 0; | ||
1880 | } | ||
1881 | |||
1752 | static const struct file_operations fuse_file_operations = { | 1882 | static const struct file_operations fuse_file_operations = { |
1753 | .llseek = fuse_file_llseek, | 1883 | .llseek = fuse_file_llseek, |
1754 | .read = do_sync_read, | 1884 | .read = do_sync_read, |
@@ -1765,6 +1895,7 @@ static const struct file_operations fuse_file_operations = { | |||
1765 | .splice_read = generic_file_splice_read, | 1895 | .splice_read = generic_file_splice_read, |
1766 | .unlocked_ioctl = fuse_file_ioctl, | 1896 | .unlocked_ioctl = fuse_file_ioctl, |
1767 | .compat_ioctl = fuse_file_compat_ioctl, | 1897 | .compat_ioctl = fuse_file_compat_ioctl, |
1898 | .poll = fuse_file_poll, | ||
1768 | }; | 1899 | }; |
1769 | 1900 | ||
1770 | static const struct file_operations fuse_direct_io_file_operations = { | 1901 | static const struct file_operations fuse_direct_io_file_operations = { |
@@ -1779,6 +1910,7 @@ static const struct file_operations fuse_direct_io_file_operations = { | |||
1779 | .flock = fuse_file_flock, | 1910 | .flock = fuse_file_flock, |
1780 | .unlocked_ioctl = fuse_file_ioctl, | 1911 | .unlocked_ioctl = fuse_file_ioctl, |
1781 | .compat_ioctl = fuse_file_compat_ioctl, | 1912 | .compat_ioctl = fuse_file_compat_ioctl, |
1913 | .poll = fuse_file_poll, | ||
1782 | /* no mmap and splice_read */ | 1914 | /* no mmap and splice_read */ |
1783 | }; | 1915 | }; |
1784 | 1916 | ||