aboutsummaryrefslogtreecommitdiffstats
path: root/kernel
diff options
context:
space:
mode:
Diffstat (limited to 'kernel')
-rw-r--r--kernel/dev.c17
-rw-r--r--kernel/file.c19
-rw-r--r--kernel/fuse_i.h4
3 files changed, 29 insertions, 11 deletions
diff --git a/kernel/dev.c b/kernel/dev.c
index 0f4de86..2c71a79 100644
--- a/kernel/dev.c
+++ b/kernel/dev.c
@@ -163,11 +163,13 @@ static void fuse_putback_request(struct fuse_conn *fc, struct fuse_req *req)
else
fuse_request_free(req);
- /* If we are in debt decrease that first */
- if (fc->outstanding_debt)
- fc->outstanding_debt--;
- else
- up(&fc->outstanding_sem);
+ if (!req->unaccounted) {
+ /* If we are in debt decrease that first */
+ if (fc->outstanding_debt)
+ fc->outstanding_debt--;
+ else
+ up(&fc->outstanding_sem);
+ }
spin_unlock(&fuse_lock);
}
@@ -322,9 +324,10 @@ static void queue_request(struct fuse_conn *fc, struct fuse_req *req)
req->in.h.unique = fc->reqctr;
req->in.h.len = sizeof(struct fuse_in_header) +
len_args(req->in.numargs, (struct fuse_arg *) req->in.args);
- if (!req->preallocated) {
+ if (!req->preallocated && !req->unaccounted) {
/* If request is not preallocated (either FORGET or
- RELEASE), then still decrease outstanding_sem, so
+ RELEASE), and is not unaccounted (SETLKW),
+ then still decrease outstanding_sem, so
user can't open infinite number of files while not
processing the RELEASE requests. However for
efficiency do it without blocking, so if down()
diff --git a/kernel/file.c b/kernel/file.c
index 9cf7413..5ceea6e 100644
--- a/kernel/file.c
+++ b/kernel/file.c
@@ -686,18 +686,29 @@ static int fuse_setlk(struct file *file, struct file_lock *fl)
struct fuse_conn *fc = get_fuse_conn(inode);
struct fuse_req *req;
struct fuse_lk_in_out arg;
+ int sleep = fl->fl_flags & FL_SLEEP;
int err;
if (fc->no_lk)
return posix_lock_file_wait(file, fl);
- req = fuse_get_request(fc);
- if (!req)
- return -EINTR;
+ if (!sleep) {
+ req = fuse_get_request(fc);
+ if (!req)
+ return -EINTR;
+ } else {
+ /* SETLKW can wait indefinately so we do not use up a
+ request from the pool, but allocate an unaccounted
+ new one */
+ req = fuse_request_alloc();
+ if (!req)
+ return -ENOMEM;
+ req->unaccounted = 1;
+ }
memset(&arg, 0, sizeof(arg));
convert_file_lock(fl, &arg.lk);
- req->in.h.opcode = (fl->fl_flags & FL_SLEEP) ? FUSE_SETLKW : FUSE_SETLK;
+ req->in.h.opcode = sleep ? FUSE_SETLKW : FUSE_SETLK;
req->in.h.nodeid = get_node_id(inode);
req->inode = inode;
req->in.numargs = 1;
diff --git a/kernel/fuse_i.h b/kernel/fuse_i.h
index be20e74..7843a96 100644
--- a/kernel/fuse_i.h
+++ b/kernel/fuse_i.h
@@ -202,6 +202,9 @@ struct fuse_req {
/** The request is preallocated */
unsigned preallocated:1;
+ /** The request is not accounted via outstanding_{sem,debt} */
+ unsigned unaccounted:1;
+
/** The request was interrupted */
unsigned interrupted:1;
@@ -337,6 +340,7 @@ struct fuse_conn {
/** Is removexattr not implemented by fs? */
unsigned no_removexattr : 1;
+ /** Are file locking primitives implemented by fs? */
unsigned no_lk : 1;
#ifdef KERNEL_2_6