[PATCH] FUSE - mount options
This patch adds miscellaneous mount options to the FUSE filesystem. The following mount options are added: o default_permissions: check permissions with generic_permission() o allow_other: allow other users to access files o allow_root: allow root to access files o kernel_cache: don't invalidate page cache on open Signed-off-by: Miklos Szeredi <miklos@szeredi.hu> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
This commit is contained in:

committed by
Linus Torvalds

parent
b6aeadeda2
commit
1e9a4ed939
@@ -26,7 +26,7 @@ static inline struct fuse_conn *fuse_get_conn(struct file *file)
|
||||
struct fuse_conn *fc;
|
||||
spin_lock(&fuse_lock);
|
||||
fc = file->private_data;
|
||||
if (fc && !fc->sb)
|
||||
if (fc && !fc->mounted)
|
||||
fc = NULL;
|
||||
spin_unlock(&fuse_lock);
|
||||
return fc;
|
||||
@@ -148,6 +148,17 @@ void fuse_put_request(struct fuse_conn *fc, struct fuse_req *req)
|
||||
fuse_putback_request(fc, req);
|
||||
}
|
||||
|
||||
void fuse_release_background(struct fuse_req *req)
|
||||
{
|
||||
iput(req->inode);
|
||||
iput(req->inode2);
|
||||
if (req->file)
|
||||
fput(req->file);
|
||||
spin_lock(&fuse_lock);
|
||||
list_del(&req->bg_entry);
|
||||
spin_unlock(&fuse_lock);
|
||||
}
|
||||
|
||||
/*
|
||||
* This function is called when a request is finished. Either a reply
|
||||
* has arrived or it was interrupted (and not yet sent) or some error
|
||||
@@ -166,12 +177,10 @@ static void request_end(struct fuse_conn *fc, struct fuse_req *req)
|
||||
putback = atomic_dec_and_test(&req->count);
|
||||
spin_unlock(&fuse_lock);
|
||||
if (req->background) {
|
||||
if (req->inode)
|
||||
iput(req->inode);
|
||||
if (req->inode2)
|
||||
iput(req->inode2);
|
||||
if (req->file)
|
||||
fput(req->file);
|
||||
down_read(&fc->sbput_sem);
|
||||
if (fc->mounted)
|
||||
fuse_release_background(req);
|
||||
up_read(&fc->sbput_sem);
|
||||
}
|
||||
wake_up(&req->waitq);
|
||||
if (req->in.h.opcode == FUSE_INIT) {
|
||||
@@ -191,11 +200,39 @@ static void request_end(struct fuse_conn *fc, struct fuse_req *req)
|
||||
fuse_putback_request(fc, req);
|
||||
}
|
||||
|
||||
static void background_request(struct fuse_req *req)
|
||||
/*
|
||||
* Unfortunately request interruption not just solves the deadlock
|
||||
* problem, it causes problems too. These stem from the fact, that an
|
||||
* interrupted request is continued to be processed in userspace,
|
||||
* while all the locks and object references (inode and file) held
|
||||
* during the operation are released.
|
||||
*
|
||||
* To release the locks is exactly why there's a need to interrupt the
|
||||
* request, so there's not a lot that can be done about this, except
|
||||
* introduce additional locking in userspace.
|
||||
*
|
||||
* More important is to keep inode and file references until userspace
|
||||
* has replied, otherwise FORGET and RELEASE could be sent while the
|
||||
* inode/file is still used by the filesystem.
|
||||
*
|
||||
* For this reason the concept of "background" request is introduced.
|
||||
* An interrupted request is backgrounded if it has been already sent
|
||||
* to userspace. Backgrounding involves getting an extra reference to
|
||||
* inode(s) or file used in the request, and adding the request to
|
||||
* fc->background list. When a reply is received for a background
|
||||
* request, the object references are released, and the request is
|
||||
* removed from the list. If the filesystem is unmounted while there
|
||||
* are still background requests, the list is walked and references
|
||||
* are released as if a reply was received.
|
||||
*
|
||||
* There's one more use for a background request. The RELEASE message is
|
||||
* always sent as background, since it doesn't return an error or
|
||||
* data.
|
||||
*/
|
||||
static void background_request(struct fuse_conn *fc, struct fuse_req *req)
|
||||
{
|
||||
/* Need to get hold of the inode(s) and/or file used in the
|
||||
request, so FORGET and RELEASE are not sent too early */
|
||||
req->background = 1;
|
||||
list_add(&req->bg_entry, &fc->background);
|
||||
if (req->inode)
|
||||
req->inode = igrab(req->inode);
|
||||
if (req->inode2)
|
||||
@@ -215,7 +252,8 @@ static int request_wait_answer_nonint(struct fuse_req *req)
|
||||
}
|
||||
|
||||
/* Called with fuse_lock held. Releases, and then reacquires it. */
|
||||
static void request_wait_answer(struct fuse_req *req, int interruptible)
|
||||
static void request_wait_answer(struct fuse_conn *fc, struct fuse_req *req,
|
||||
int interruptible)
|
||||
{
|
||||
int intr;
|
||||
|
||||
@@ -255,7 +293,7 @@ static void request_wait_answer(struct fuse_req *req, int interruptible)
|
||||
list_del(&req->list);
|
||||
__fuse_put_request(req);
|
||||
} else if (!req->finished && req->sent)
|
||||
background_request(req);
|
||||
background_request(fc, req);
|
||||
}
|
||||
|
||||
static unsigned len_args(unsigned numargs, struct fuse_arg *args)
|
||||
@@ -297,7 +335,7 @@ static void request_send_wait(struct fuse_conn *fc, struct fuse_req *req,
|
||||
{
|
||||
req->isreply = 1;
|
||||
spin_lock(&fuse_lock);
|
||||
if (!fc->file)
|
||||
if (!fc->connected)
|
||||
req->out.h.error = -ENOTCONN;
|
||||
else if (fc->conn_error)
|
||||
req->out.h.error = -ECONNREFUSED;
|
||||
@@ -307,7 +345,7 @@ static void request_send_wait(struct fuse_conn *fc, struct fuse_req *req,
|
||||
after request_end() */
|
||||
__fuse_get_request(req);
|
||||
|
||||
request_wait_answer(req, interruptible);
|
||||
request_wait_answer(fc, req, interruptible);
|
||||
}
|
||||
spin_unlock(&fuse_lock);
|
||||
}
|
||||
@@ -330,7 +368,7 @@ void request_send_nonint(struct fuse_conn *fc, struct fuse_req *req)
|
||||
static void request_send_nowait(struct fuse_conn *fc, struct fuse_req *req)
|
||||
{
|
||||
spin_lock(&fuse_lock);
|
||||
if (fc->file) {
|
||||
if (fc->connected) {
|
||||
queue_request(fc, req);
|
||||
spin_unlock(&fuse_lock);
|
||||
} else {
|
||||
@@ -348,7 +386,9 @@ void request_send_noreply(struct fuse_conn *fc, struct fuse_req *req)
|
||||
void request_send_background(struct fuse_conn *fc, struct fuse_req *req)
|
||||
{
|
||||
req->isreply = 1;
|
||||
background_request(req);
|
||||
spin_lock(&fuse_lock);
|
||||
background_request(fc, req);
|
||||
spin_unlock(&fuse_lock);
|
||||
request_send_nowait(fc, req);
|
||||
}
|
||||
|
||||
@@ -583,7 +623,7 @@ static void request_wait(struct fuse_conn *fc)
|
||||
DECLARE_WAITQUEUE(wait, current);
|
||||
|
||||
add_wait_queue_exclusive(&fc->waitq, &wait);
|
||||
while (fc->sb && list_empty(&fc->pending)) {
|
||||
while (fc->mounted && list_empty(&fc->pending)) {
|
||||
set_current_state(TASK_INTERRUPTIBLE);
|
||||
if (signal_pending(current))
|
||||
break;
|
||||
@@ -622,7 +662,7 @@ static ssize_t fuse_dev_readv(struct file *file, const struct iovec *iov,
|
||||
goto err_unlock;
|
||||
request_wait(fc);
|
||||
err = -ENODEV;
|
||||
if (!fc->sb)
|
||||
if (!fc->mounted)
|
||||
goto err_unlock;
|
||||
err = -ERESTARTSYS;
|
||||
if (list_empty(&fc->pending))
|
||||
@@ -839,7 +879,7 @@ static int fuse_dev_release(struct inode *inode, struct file *file)
|
||||
spin_lock(&fuse_lock);
|
||||
fc = file->private_data;
|
||||
if (fc) {
|
||||
fc->file = NULL;
|
||||
fc->connected = 0;
|
||||
end_requests(fc, &fc->pending);
|
||||
end_requests(fc, &fc->processing);
|
||||
fuse_release_conn(fc);
|
||||
|
Reference in New Issue
Block a user