aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMiklos Szeredi <mszeredi@suse.cz>2011-08-08 10:08:08 -0400
committerMiklos Szeredi <mszeredi@suse.cz>2011-08-08 10:08:08 -0400
commit37fb3a30b46237f23cfdf7ee09d49f9888dd13bf (patch)
treec36910e300ade812159d12218fdf122b3d2ef3de
parenta2daff6803a384ce065e3681a2affea1da59c5f5 (diff)
fuse: fix flock
Commit a9ff4f87 "fuse: support BSD locking semantics" overlooked a number of issues with supporing flock locks over existing POSIX locking infrastructure: - it's not backward compatible, passing flock(2) calls to userspace unconditionally (if userspace sets FUSE_POSIX_LOCKS) - it doesn't cater for the fact that flock locks are automatically unlocked on file release - it doesn't take into account the fact that flock exclusive locks (write locks) don't need an fd opened for write. The last one invalidates the original premise of the patch that flock locks can be emulated with POSIX locks. This patch fixes the first two issues. The last one needs to be fixed in userspace if the filesystem assumed that a write lock will happen only on a file operned for write (as in the case of the current fuse library). Reported-by: Sebastian Pipping <webmaster@hartwork.org> Signed-off-by: Miklos Szeredi <mszeredi@suse.cz>
-rw-r--r--fs/fuse/file.c11
-rw-r--r--fs/fuse/fuse_i.h8
-rw-r--r--fs/fuse/inode.c8
-rw-r--r--include/linux/fuse.h9
4 files changed, 32 insertions, 4 deletions
diff --git a/fs/fuse/file.c b/fs/fuse/file.c
index 82a66466a24..e3278492435 100644
--- a/fs/fuse/file.c
+++ b/fs/fuse/file.c
@@ -245,6 +245,12 @@ void fuse_release_common(struct file *file, int opcode)
245 req = ff->reserved_req; 245 req = ff->reserved_req;
246 fuse_prepare_release(ff, file->f_flags, opcode); 246 fuse_prepare_release(ff, file->f_flags, opcode);
247 247
248 if (ff->flock) {
249 struct fuse_release_in *inarg = &req->misc.release.in;
250 inarg->release_flags |= FUSE_RELEASE_FLOCK_UNLOCK;
251 inarg->lock_owner = fuse_lock_owner_id(ff->fc,
252 (fl_owner_t) file);
253 }
248 /* Hold vfsmount and dentry until release is finished */ 254 /* Hold vfsmount and dentry until release is finished */
249 path_get(&file->f_path); 255 path_get(&file->f_path);
250 req->misc.release.path = file->f_path; 256 req->misc.release.path = file->f_path;
@@ -1547,11 +1553,14 @@ static int fuse_file_flock(struct file *file, int cmd, struct file_lock *fl)
1547 struct fuse_conn *fc = get_fuse_conn(inode); 1553 struct fuse_conn *fc = get_fuse_conn(inode);
1548 int err; 1554 int err;
1549 1555
1550 if (fc->no_lock) { 1556 if (fc->no_flock) {
1551 err = flock_lock_file_wait(file, fl); 1557 err = flock_lock_file_wait(file, fl);
1552 } else { 1558 } else {
1559 struct fuse_file *ff = file->private_data;
1560
1553 /* emulate flock with POSIX locks */ 1561 /* emulate flock with POSIX locks */
1554 fl->fl_owner = (fl_owner_t) file; 1562 fl->fl_owner = (fl_owner_t) file;
1563 ff->flock = true;
1555 err = fuse_setlk(file, fl, 1); 1564 err = fuse_setlk(file, fl, 1);
1556 } 1565 }
1557 1566
diff --git a/fs/fuse/fuse_i.h b/fs/fuse/fuse_i.h
index b788becada7..eb8c6135fbb 100644
--- a/fs/fuse/fuse_i.h
+++ b/fs/fuse/fuse_i.h
@@ -135,6 +135,9 @@ struct fuse_file {
135 135
136 /** Wait queue head for poll */ 136 /** Wait queue head for poll */
137 wait_queue_head_t poll_wait; 137 wait_queue_head_t poll_wait;
138
139 /** Has flock been performed on this file? */
140 bool flock:1;
138}; 141};
139 142
140/** One input argument of a request */ 143/** One input argument of a request */
@@ -448,7 +451,7 @@ struct fuse_conn {
448 /** Is removexattr not implemented by fs? */ 451 /** Is removexattr not implemented by fs? */
449 unsigned no_removexattr:1; 452 unsigned no_removexattr:1;
450 453
451 /** Are file locking primitives not implemented by fs? */ 454 /** Are posix file locking primitives not implemented by fs? */
452 unsigned no_lock:1; 455 unsigned no_lock:1;
453 456
454 /** Is access not implemented by fs? */ 457 /** Is access not implemented by fs? */
@@ -472,6 +475,9 @@ struct fuse_conn {
472 /** Don't apply umask to creation modes */ 475 /** Don't apply umask to creation modes */
473 unsigned dont_mask:1; 476 unsigned dont_mask:1;
474 477
478 /** Are BSD file locking primitives not implemented by fs? */
479 unsigned no_flock:1;
480
475 /** The number of requests waiting for completion */ 481 /** The number of requests waiting for completion */
476 atomic_t num_waiting; 482 atomic_t num_waiting;
477 483
diff --git a/fs/fuse/inode.c b/fs/fuse/inode.c
index 5354906e797..f541d639844 100644
--- a/fs/fuse/inode.c
+++ b/fs/fuse/inode.c
@@ -809,6 +809,10 @@ static void process_init_reply(struct fuse_conn *fc, struct fuse_req *req)
809 fc->async_read = 1; 809 fc->async_read = 1;
810 if (!(arg->flags & FUSE_POSIX_LOCKS)) 810 if (!(arg->flags & FUSE_POSIX_LOCKS))
811 fc->no_lock = 1; 811 fc->no_lock = 1;
812 if (arg->minor >= 17) {
813 if (!(arg->flags & FUSE_FLOCK_LOCKS))
814 fc->no_flock = 1;
815 }
812 if (arg->flags & FUSE_ATOMIC_O_TRUNC) 816 if (arg->flags & FUSE_ATOMIC_O_TRUNC)
813 fc->atomic_o_trunc = 1; 817 fc->atomic_o_trunc = 1;
814 if (arg->minor >= 9) { 818 if (arg->minor >= 9) {
@@ -823,6 +827,7 @@ static void process_init_reply(struct fuse_conn *fc, struct fuse_req *req)
823 } else { 827 } else {
824 ra_pages = fc->max_read / PAGE_CACHE_SIZE; 828 ra_pages = fc->max_read / PAGE_CACHE_SIZE;
825 fc->no_lock = 1; 829 fc->no_lock = 1;
830 fc->no_flock = 1;
826 } 831 }
827 832
828 fc->bdi.ra_pages = min(fc->bdi.ra_pages, ra_pages); 833 fc->bdi.ra_pages = min(fc->bdi.ra_pages, ra_pages);
@@ -843,7 +848,8 @@ static void fuse_send_init(struct fuse_conn *fc, struct fuse_req *req)
843 arg->minor = FUSE_KERNEL_MINOR_VERSION; 848 arg->minor = FUSE_KERNEL_MINOR_VERSION;
844 arg->max_readahead = fc->bdi.ra_pages * PAGE_CACHE_SIZE; 849 arg->max_readahead = fc->bdi.ra_pages * PAGE_CACHE_SIZE;
845 arg->flags |= FUSE_ASYNC_READ | FUSE_POSIX_LOCKS | FUSE_ATOMIC_O_TRUNC | 850 arg->flags |= FUSE_ASYNC_READ | FUSE_POSIX_LOCKS | FUSE_ATOMIC_O_TRUNC |
846 FUSE_EXPORT_SUPPORT | FUSE_BIG_WRITES | FUSE_DONT_MASK; 851 FUSE_EXPORT_SUPPORT | FUSE_BIG_WRITES | FUSE_DONT_MASK |
852 FUSE_FLOCK_LOCKS;
847 req->in.h.opcode = FUSE_INIT; 853 req->in.h.opcode = FUSE_INIT;
848 req->in.numargs = 1; 854 req->in.numargs = 1;
849 req->in.args[0].size = sizeof(*arg); 855 req->in.args[0].size = sizeof(*arg);
diff --git a/include/linux/fuse.h b/include/linux/fuse.h
index d464de53db4..464cff52686 100644
--- a/include/linux/fuse.h
+++ b/include/linux/fuse.h
@@ -47,6 +47,9 @@
47 * - FUSE_IOCTL_UNRESTRICTED shall now return with array of 'struct 47 * - FUSE_IOCTL_UNRESTRICTED shall now return with array of 'struct
48 * fuse_ioctl_iovec' instead of ambiguous 'struct iovec' 48 * fuse_ioctl_iovec' instead of ambiguous 'struct iovec'
49 * - add FUSE_IOCTL_32BIT flag 49 * - add FUSE_IOCTL_32BIT flag
50 *
51 * 7.17
52 * - add FUSE_FLOCK_LOCKS and FUSE_RELEASE_FLOCK_UNLOCK
50 */ 53 */
51 54
52#ifndef _LINUX_FUSE_H 55#ifndef _LINUX_FUSE_H
@@ -78,7 +81,7 @@
78#define FUSE_KERNEL_VERSION 7 81#define FUSE_KERNEL_VERSION 7
79 82
80/** Minor version number of this interface */ 83/** Minor version number of this interface */
81#define FUSE_KERNEL_MINOR_VERSION 16 84#define FUSE_KERNEL_MINOR_VERSION 17
82 85
83/** The node ID of the root inode */ 86/** The node ID of the root inode */
84#define FUSE_ROOT_ID 1 87#define FUSE_ROOT_ID 1
@@ -153,8 +156,10 @@ struct fuse_file_lock {
153/** 156/**
154 * INIT request/reply flags 157 * INIT request/reply flags
155 * 158 *
159 * FUSE_POSIX_LOCKS: remote locking for POSIX file locks
156 * FUSE_EXPORT_SUPPORT: filesystem handles lookups of "." and ".." 160 * FUSE_EXPORT_SUPPORT: filesystem handles lookups of "." and ".."
157 * FUSE_DONT_MASK: don't apply umask to file mode on create operations 161 * FUSE_DONT_MASK: don't apply umask to file mode on create operations
162 * FUSE_FLOCK_LOCKS: remote locking for BSD style file locks
158 */ 163 */
159#define FUSE_ASYNC_READ (1 << 0) 164#define FUSE_ASYNC_READ (1 << 0)
160#define FUSE_POSIX_LOCKS (1 << 1) 165#define FUSE_POSIX_LOCKS (1 << 1)
@@ -163,6 +168,7 @@ struct fuse_file_lock {
163#define FUSE_EXPORT_SUPPORT (1 << 4) 168#define FUSE_EXPORT_SUPPORT (1 << 4)
164#define FUSE_BIG_WRITES (1 << 5) 169#define FUSE_BIG_WRITES (1 << 5)
165#define FUSE_DONT_MASK (1 << 6) 170#define FUSE_DONT_MASK (1 << 6)
171#define FUSE_FLOCK_LOCKS (1 << 10)
166 172
167/** 173/**
168 * CUSE INIT request/reply flags 174 * CUSE INIT request/reply flags
@@ -175,6 +181,7 @@ struct fuse_file_lock {
175 * Release flags 181 * Release flags
176 */ 182 */
177#define FUSE_RELEASE_FLUSH (1 << 0) 183#define FUSE_RELEASE_FLUSH (1 << 0)
184#define FUSE_RELEASE_FLOCK_UNLOCK (1 << 1)
178 185
179/** 186/**
180 * Getattr flags 187 * Getattr flags