Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mszeredi/fuse
Pull fuse updates from Miklos Szeredi: "This is the start of improving fuse scalability. An input queue and a processing queue is split out from the monolithic fuse connection, each of those having their own spinlock. The end of the patchset adds the ability to clone a fuse connection. This means, that instead of having to read/write requests/answers on a single fuse device fd, the fuse daemon can have multiple distinct file descriptors open. Each of those can be used to receive requests and send answers, currently the only constraint is that a request must be answered on the same fd as it was read from. This can be extended further to allow binding a device clone to a specific CPU or NUMA node. Based on a patchset by Srinivas Eeda and Ashish Samant. Thanks to Ashish for the review of this series" * 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mszeredi/fuse: (40 commits) fuse: update MAINTAINERS entry fuse: separate pqueue for clones fuse: introduce per-instance fuse_dev structure fuse: device fd clone fuse: abort: no fc->lock needed for request ending fuse: no fc->lock for pqueue parts fuse: no fc->lock in request_end() fuse: cleanup request_end() fuse: request_end(): do once fuse: add req flag for private list fuse: pqueue locking fuse: abort: group pqueue accesses fuse: cleanup fuse_dev_do_read() fuse: move list_del_init() from request_end() into callers fuse: duplicate ->connected in pqueue fuse: separate out processing queue fuse: simplify request_wait() fuse: no fc->lock for iqueue parts fuse: allow interrupt queuing without fc->lock fuse: iqueue locking ...
This commit is contained in:
commit
a7ba4bf5e7
|
@ -321,6 +321,7 @@ Code Seq#(hex) Include File Comments
|
||||||
0xDB 00-0F drivers/char/mwave/mwavepub.h
|
0xDB 00-0F drivers/char/mwave/mwavepub.h
|
||||||
0xDD 00-3F ZFCP device driver see drivers/s390/scsi/
|
0xDD 00-3F ZFCP device driver see drivers/s390/scsi/
|
||||||
<mailto:aherrman@de.ibm.com>
|
<mailto:aherrman@de.ibm.com>
|
||||||
|
0xE5 00-3F linux/fuse.h
|
||||||
0xEC 00-01 drivers/platform/chrome/cros_ec_dev.h ChromeOS EC driver
|
0xEC 00-01 drivers/platform/chrome/cros_ec_dev.h ChromeOS EC driver
|
||||||
0xF3 00-3F drivers/usb/misc/sisusbvga/sisusb.h sisfb (in development)
|
0xF3 00-3F drivers/usb/misc/sisusbvga/sisusb.h sisfb (in development)
|
||||||
<mailto:thomas@winischhofer.net>
|
<mailto:thomas@winischhofer.net>
|
||||||
|
|
|
@ -4430,9 +4430,11 @@ FUSE: FILESYSTEM IN USERSPACE
|
||||||
M: Miklos Szeredi <miklos@szeredi.hu>
|
M: Miklos Szeredi <miklos@szeredi.hu>
|
||||||
L: fuse-devel@lists.sourceforge.net
|
L: fuse-devel@lists.sourceforge.net
|
||||||
W: http://fuse.sourceforge.net/
|
W: http://fuse.sourceforge.net/
|
||||||
|
T: git git://git.kernel.org/pub/scm/linux/kernel/git/mszeredi/fuse.git
|
||||||
S: Maintained
|
S: Maintained
|
||||||
F: fs/fuse/
|
F: fs/fuse/
|
||||||
F: include/uapi/linux/fuse.h
|
F: include/uapi/linux/fuse.h
|
||||||
|
F: Documentation/filesystems/fuse.txt
|
||||||
|
|
||||||
FUTURE DOMAIN TMC-16x0 SCSI DRIVER (16-bit)
|
FUTURE DOMAIN TMC-16x0 SCSI DRIVER (16-bit)
|
||||||
M: Rik Faith <faith@cs.unc.edu>
|
M: Rik Faith <faith@cs.unc.edu>
|
||||||
|
|
|
@ -489,6 +489,7 @@ static void cuse_fc_release(struct fuse_conn *fc)
|
||||||
*/
|
*/
|
||||||
static int cuse_channel_open(struct inode *inode, struct file *file)
|
static int cuse_channel_open(struct inode *inode, struct file *file)
|
||||||
{
|
{
|
||||||
|
struct fuse_dev *fud;
|
||||||
struct cuse_conn *cc;
|
struct cuse_conn *cc;
|
||||||
int rc;
|
int rc;
|
||||||
|
|
||||||
|
@ -499,17 +500,22 @@ static int cuse_channel_open(struct inode *inode, struct file *file)
|
||||||
|
|
||||||
fuse_conn_init(&cc->fc);
|
fuse_conn_init(&cc->fc);
|
||||||
|
|
||||||
|
fud = fuse_dev_alloc(&cc->fc);
|
||||||
|
if (!fud) {
|
||||||
|
kfree(cc);
|
||||||
|
return -ENOMEM;
|
||||||
|
}
|
||||||
|
|
||||||
INIT_LIST_HEAD(&cc->list);
|
INIT_LIST_HEAD(&cc->list);
|
||||||
cc->fc.release = cuse_fc_release;
|
cc->fc.release = cuse_fc_release;
|
||||||
|
|
||||||
cc->fc.connected = 1;
|
|
||||||
cc->fc.initialized = 1;
|
cc->fc.initialized = 1;
|
||||||
rc = cuse_send_init(cc);
|
rc = cuse_send_init(cc);
|
||||||
if (rc) {
|
if (rc) {
|
||||||
fuse_conn_put(&cc->fc);
|
fuse_dev_free(fud);
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
file->private_data = &cc->fc; /* channel owns base reference to cc */
|
file->private_data = fud;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -527,7 +533,8 @@ static int cuse_channel_open(struct inode *inode, struct file *file)
|
||||||
*/
|
*/
|
||||||
static int cuse_channel_release(struct inode *inode, struct file *file)
|
static int cuse_channel_release(struct inode *inode, struct file *file)
|
||||||
{
|
{
|
||||||
struct cuse_conn *cc = fc_to_cc(file->private_data);
|
struct fuse_dev *fud = file->private_data;
|
||||||
|
struct cuse_conn *cc = fc_to_cc(fud->fc);
|
||||||
int rc;
|
int rc;
|
||||||
|
|
||||||
/* remove from the conntbl, no more access from this point on */
|
/* remove from the conntbl, no more access from this point on */
|
||||||
|
|
833
fs/fuse/dev.c
833
fs/fuse/dev.c
File diff suppressed because it is too large
Load diff
|
@ -96,17 +96,17 @@ static void fuse_file_put(struct fuse_file *ff, bool sync)
|
||||||
* Drop the release request when client does not
|
* Drop the release request when client does not
|
||||||
* implement 'open'
|
* implement 'open'
|
||||||
*/
|
*/
|
||||||
req->background = 0;
|
__clear_bit(FR_BACKGROUND, &req->flags);
|
||||||
iput(req->misc.release.inode);
|
iput(req->misc.release.inode);
|
||||||
fuse_put_request(ff->fc, req);
|
fuse_put_request(ff->fc, req);
|
||||||
} else if (sync) {
|
} else if (sync) {
|
||||||
req->background = 0;
|
__clear_bit(FR_BACKGROUND, &req->flags);
|
||||||
fuse_request_send(ff->fc, req);
|
fuse_request_send(ff->fc, req);
|
||||||
iput(req->misc.release.inode);
|
iput(req->misc.release.inode);
|
||||||
fuse_put_request(ff->fc, req);
|
fuse_put_request(ff->fc, req);
|
||||||
} else {
|
} else {
|
||||||
req->end = fuse_release_end;
|
req->end = fuse_release_end;
|
||||||
req->background = 1;
|
__set_bit(FR_BACKGROUND, &req->flags);
|
||||||
fuse_request_send_background(ff->fc, req);
|
fuse_request_send_background(ff->fc, req);
|
||||||
}
|
}
|
||||||
kfree(ff);
|
kfree(ff);
|
||||||
|
@ -299,8 +299,8 @@ void fuse_sync_release(struct fuse_file *ff, int flags)
|
||||||
{
|
{
|
||||||
WARN_ON(atomic_read(&ff->count) > 1);
|
WARN_ON(atomic_read(&ff->count) > 1);
|
||||||
fuse_prepare_release(ff, flags, FUSE_RELEASE);
|
fuse_prepare_release(ff, flags, FUSE_RELEASE);
|
||||||
ff->reserved_req->force = 1;
|
__set_bit(FR_FORCE, &ff->reserved_req->flags);
|
||||||
ff->reserved_req->background = 0;
|
__clear_bit(FR_BACKGROUND, &ff->reserved_req->flags);
|
||||||
fuse_request_send(ff->fc, ff->reserved_req);
|
fuse_request_send(ff->fc, ff->reserved_req);
|
||||||
fuse_put_request(ff->fc, ff->reserved_req);
|
fuse_put_request(ff->fc, ff->reserved_req);
|
||||||
kfree(ff);
|
kfree(ff);
|
||||||
|
@ -426,7 +426,7 @@ static int fuse_flush(struct file *file, fl_owner_t id)
|
||||||
req->in.numargs = 1;
|
req->in.numargs = 1;
|
||||||
req->in.args[0].size = sizeof(inarg);
|
req->in.args[0].size = sizeof(inarg);
|
||||||
req->in.args[0].value = &inarg;
|
req->in.args[0].value = &inarg;
|
||||||
req->force = 1;
|
__set_bit(FR_FORCE, &req->flags);
|
||||||
fuse_request_send(fc, req);
|
fuse_request_send(fc, req);
|
||||||
err = req->out.h.error;
|
err = req->out.h.error;
|
||||||
fuse_put_request(fc, req);
|
fuse_put_request(fc, req);
|
||||||
|
@ -1611,7 +1611,8 @@ static int fuse_writepage_locked(struct page *page)
|
||||||
if (!req)
|
if (!req)
|
||||||
goto err;
|
goto err;
|
||||||
|
|
||||||
req->background = 1; /* writeback always goes to bg_queue */
|
/* writeback always goes to bg_queue */
|
||||||
|
__set_bit(FR_BACKGROUND, &req->flags);
|
||||||
tmp_page = alloc_page(GFP_NOFS | __GFP_HIGHMEM);
|
tmp_page = alloc_page(GFP_NOFS | __GFP_HIGHMEM);
|
||||||
if (!tmp_page)
|
if (!tmp_page)
|
||||||
goto err_free;
|
goto err_free;
|
||||||
|
@ -1742,8 +1743,7 @@ static bool fuse_writepage_in_flight(struct fuse_req *new_req,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (old_req->num_pages == 1 && (old_req->state == FUSE_REQ_INIT ||
|
if (old_req->num_pages == 1 && test_bit(FR_PENDING, &old_req->flags)) {
|
||||||
old_req->state == FUSE_REQ_PENDING)) {
|
|
||||||
struct backing_dev_info *bdi = inode_to_bdi(page->mapping->host);
|
struct backing_dev_info *bdi = inode_to_bdi(page->mapping->host);
|
||||||
|
|
||||||
copy_highpage(old_req->pages[0], page);
|
copy_highpage(old_req->pages[0], page);
|
||||||
|
@ -1830,7 +1830,7 @@ static int fuse_writepages_fill(struct page *page,
|
||||||
req->misc.write.in.write_flags |= FUSE_WRITE_CACHE;
|
req->misc.write.in.write_flags |= FUSE_WRITE_CACHE;
|
||||||
req->misc.write.next = NULL;
|
req->misc.write.next = NULL;
|
||||||
req->in.argpages = 1;
|
req->in.argpages = 1;
|
||||||
req->background = 1;
|
__set_bit(FR_BACKGROUND, &req->flags);
|
||||||
req->num_pages = 0;
|
req->num_pages = 0;
|
||||||
req->end = fuse_writepage_end;
|
req->end = fuse_writepage_end;
|
||||||
req->inode = inode;
|
req->inode = inode;
|
||||||
|
|
167
fs/fuse/fuse_i.h
167
fs/fuse/fuse_i.h
|
@ -241,16 +241,6 @@ struct fuse_args {
|
||||||
|
|
||||||
#define FUSE_ARGS(args) struct fuse_args args = {}
|
#define FUSE_ARGS(args) struct fuse_args args = {}
|
||||||
|
|
||||||
/** The request state */
|
|
||||||
enum fuse_req_state {
|
|
||||||
FUSE_REQ_INIT = 0,
|
|
||||||
FUSE_REQ_PENDING,
|
|
||||||
FUSE_REQ_READING,
|
|
||||||
FUSE_REQ_SENT,
|
|
||||||
FUSE_REQ_WRITING,
|
|
||||||
FUSE_REQ_FINISHED
|
|
||||||
};
|
|
||||||
|
|
||||||
/** The request IO state (for asynchronous processing) */
|
/** The request IO state (for asynchronous processing) */
|
||||||
struct fuse_io_priv {
|
struct fuse_io_priv {
|
||||||
int async;
|
int async;
|
||||||
|
@ -266,8 +256,41 @@ struct fuse_io_priv {
|
||||||
struct completion *done;
|
struct completion *done;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Request flags
|
||||||
|
*
|
||||||
|
* FR_ISREPLY: set if the request has reply
|
||||||
|
* FR_FORCE: force sending of the request even if interrupted
|
||||||
|
* FR_BACKGROUND: request is sent in the background
|
||||||
|
* FR_WAITING: request is counted as "waiting"
|
||||||
|
* FR_ABORTED: the request was aborted
|
||||||
|
* FR_INTERRUPTED: the request has been interrupted
|
||||||
|
* FR_LOCKED: data is being copied to/from the request
|
||||||
|
* FR_PENDING: request is not yet in userspace
|
||||||
|
* FR_SENT: request is in userspace, waiting for an answer
|
||||||
|
* FR_FINISHED: request is finished
|
||||||
|
* FR_PRIVATE: request is on private list
|
||||||
|
*/
|
||||||
|
enum fuse_req_flag {
|
||||||
|
FR_ISREPLY,
|
||||||
|
FR_FORCE,
|
||||||
|
FR_BACKGROUND,
|
||||||
|
FR_WAITING,
|
||||||
|
FR_ABORTED,
|
||||||
|
FR_INTERRUPTED,
|
||||||
|
FR_LOCKED,
|
||||||
|
FR_PENDING,
|
||||||
|
FR_SENT,
|
||||||
|
FR_FINISHED,
|
||||||
|
FR_PRIVATE,
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A request to the client
|
* A request to the client
|
||||||
|
*
|
||||||
|
* .waitq.lock protects the following fields:
|
||||||
|
* - FR_ABORTED
|
||||||
|
* - FR_LOCKED (may also be modified under fc->lock, tested under both)
|
||||||
*/
|
*/
|
||||||
struct fuse_req {
|
struct fuse_req {
|
||||||
/** This can be on either pending processing or io lists in
|
/** This can be on either pending processing or io lists in
|
||||||
|
@ -283,35 +306,8 @@ struct fuse_req {
|
||||||
/** Unique ID for the interrupt request */
|
/** Unique ID for the interrupt request */
|
||||||
u64 intr_unique;
|
u64 intr_unique;
|
||||||
|
|
||||||
/*
|
/* Request flags, updated with test/set/clear_bit() */
|
||||||
* The following bitfields are either set once before the
|
unsigned long flags;
|
||||||
* request is queued or setting/clearing them is protected by
|
|
||||||
* fuse_conn->lock
|
|
||||||
*/
|
|
||||||
|
|
||||||
/** True if the request has reply */
|
|
||||||
unsigned isreply:1;
|
|
||||||
|
|
||||||
/** Force sending of the request even if interrupted */
|
|
||||||
unsigned force:1;
|
|
||||||
|
|
||||||
/** The request was aborted */
|
|
||||||
unsigned aborted:1;
|
|
||||||
|
|
||||||
/** Request is sent in the background */
|
|
||||||
unsigned background:1;
|
|
||||||
|
|
||||||
/** The request has been interrupted */
|
|
||||||
unsigned interrupted:1;
|
|
||||||
|
|
||||||
/** Data is being copied to/from the request */
|
|
||||||
unsigned locked:1;
|
|
||||||
|
|
||||||
/** Request is counted as "waiting" */
|
|
||||||
unsigned waiting:1;
|
|
||||||
|
|
||||||
/** State of the request */
|
|
||||||
enum fuse_req_state state;
|
|
||||||
|
|
||||||
/** The request input */
|
/** The request input */
|
||||||
struct fuse_in in;
|
struct fuse_in in;
|
||||||
|
@ -380,6 +376,61 @@ struct fuse_req {
|
||||||
struct file *stolen_file;
|
struct file *stolen_file;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct fuse_iqueue {
|
||||||
|
/** Connection established */
|
||||||
|
unsigned connected;
|
||||||
|
|
||||||
|
/** Readers of the connection are waiting on this */
|
||||||
|
wait_queue_head_t waitq;
|
||||||
|
|
||||||
|
/** The next unique request id */
|
||||||
|
u64 reqctr;
|
||||||
|
|
||||||
|
/** The list of pending requests */
|
||||||
|
struct list_head pending;
|
||||||
|
|
||||||
|
/** Pending interrupts */
|
||||||
|
struct list_head interrupts;
|
||||||
|
|
||||||
|
/** Queue of pending forgets */
|
||||||
|
struct fuse_forget_link forget_list_head;
|
||||||
|
struct fuse_forget_link *forget_list_tail;
|
||||||
|
|
||||||
|
/** Batching of FORGET requests (positive indicates FORGET batch) */
|
||||||
|
int forget_batch;
|
||||||
|
|
||||||
|
/** O_ASYNC requests */
|
||||||
|
struct fasync_struct *fasync;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct fuse_pqueue {
|
||||||
|
/** Connection established */
|
||||||
|
unsigned connected;
|
||||||
|
|
||||||
|
/** Lock protecting accessess to members of this structure */
|
||||||
|
spinlock_t lock;
|
||||||
|
|
||||||
|
/** The list of requests being processed */
|
||||||
|
struct list_head processing;
|
||||||
|
|
||||||
|
/** The list of requests under I/O */
|
||||||
|
struct list_head io;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fuse device instance
|
||||||
|
*/
|
||||||
|
struct fuse_dev {
|
||||||
|
/** Fuse connection for this device */
|
||||||
|
struct fuse_conn *fc;
|
||||||
|
|
||||||
|
/** Processing queue */
|
||||||
|
struct fuse_pqueue pq;
|
||||||
|
|
||||||
|
/** list entry on fc->devices */
|
||||||
|
struct list_head entry;
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A Fuse connection.
|
* A Fuse connection.
|
||||||
*
|
*
|
||||||
|
@ -394,6 +445,9 @@ struct fuse_conn {
|
||||||
/** Refcount */
|
/** Refcount */
|
||||||
atomic_t count;
|
atomic_t count;
|
||||||
|
|
||||||
|
/** Number of fuse_dev's */
|
||||||
|
atomic_t dev_count;
|
||||||
|
|
||||||
struct rcu_head rcu;
|
struct rcu_head rcu;
|
||||||
|
|
||||||
/** The user id for this mount */
|
/** The user id for this mount */
|
||||||
|
@ -411,17 +465,8 @@ struct fuse_conn {
|
||||||
/** Maximum write size */
|
/** Maximum write size */
|
||||||
unsigned max_write;
|
unsigned max_write;
|
||||||
|
|
||||||
/** Readers of the connection are waiting on this */
|
/** Input queue */
|
||||||
wait_queue_head_t waitq;
|
struct fuse_iqueue iq;
|
||||||
|
|
||||||
/** The list of pending requests */
|
|
||||||
struct list_head pending;
|
|
||||||
|
|
||||||
/** The list of requests being processed */
|
|
||||||
struct list_head processing;
|
|
||||||
|
|
||||||
/** The list of requests under I/O */
|
|
||||||
struct list_head io;
|
|
||||||
|
|
||||||
/** The next unique kernel file handle */
|
/** The next unique kernel file handle */
|
||||||
u64 khctr;
|
u64 khctr;
|
||||||
|
@ -444,16 +489,6 @@ struct fuse_conn {
|
||||||
/** The list of background requests set aside for later queuing */
|
/** The list of background requests set aside for later queuing */
|
||||||
struct list_head bg_queue;
|
struct list_head bg_queue;
|
||||||
|
|
||||||
/** Pending interrupts */
|
|
||||||
struct list_head interrupts;
|
|
||||||
|
|
||||||
/** Queue of pending forgets */
|
|
||||||
struct fuse_forget_link forget_list_head;
|
|
||||||
struct fuse_forget_link *forget_list_tail;
|
|
||||||
|
|
||||||
/** Batching of FORGET requests (positive indicates FORGET batch) */
|
|
||||||
int forget_batch;
|
|
||||||
|
|
||||||
/** Flag indicating that INIT reply has been received. Allocating
|
/** Flag indicating that INIT reply has been received. Allocating
|
||||||
* any fuse request will be suspended until the flag is set */
|
* any fuse request will be suspended until the flag is set */
|
||||||
int initialized;
|
int initialized;
|
||||||
|
@ -469,9 +504,6 @@ struct fuse_conn {
|
||||||
/** waitq for reserved requests */
|
/** waitq for reserved requests */
|
||||||
wait_queue_head_t reserved_req_waitq;
|
wait_queue_head_t reserved_req_waitq;
|
||||||
|
|
||||||
/** The next unique request id */
|
|
||||||
u64 reqctr;
|
|
||||||
|
|
||||||
/** Connection established, cleared on umount, connection
|
/** Connection established, cleared on umount, connection
|
||||||
abort and device release */
|
abort and device release */
|
||||||
unsigned connected;
|
unsigned connected;
|
||||||
|
@ -594,9 +626,6 @@ struct fuse_conn {
|
||||||
/** number of dentries used in the above array */
|
/** number of dentries used in the above array */
|
||||||
int ctl_ndents;
|
int ctl_ndents;
|
||||||
|
|
||||||
/** O_ASYNC requests */
|
|
||||||
struct fasync_struct *fasync;
|
|
||||||
|
|
||||||
/** Key for lock owner ID scrambling */
|
/** Key for lock owner ID scrambling */
|
||||||
u32 scramble_key[4];
|
u32 scramble_key[4];
|
||||||
|
|
||||||
|
@ -614,6 +643,9 @@ struct fuse_conn {
|
||||||
|
|
||||||
/** Read/write semaphore to hold when accessing sb. */
|
/** Read/write semaphore to hold when accessing sb. */
|
||||||
struct rw_semaphore killsb;
|
struct rw_semaphore killsb;
|
||||||
|
|
||||||
|
/** List of device instances belonging to this connection */
|
||||||
|
struct list_head devices;
|
||||||
};
|
};
|
||||||
|
|
||||||
static inline struct fuse_conn *get_fuse_conn_super(struct super_block *sb)
|
static inline struct fuse_conn *get_fuse_conn_super(struct super_block *sb)
|
||||||
|
@ -826,6 +858,9 @@ void fuse_conn_init(struct fuse_conn *fc);
|
||||||
*/
|
*/
|
||||||
void fuse_conn_put(struct fuse_conn *fc);
|
void fuse_conn_put(struct fuse_conn *fc);
|
||||||
|
|
||||||
|
struct fuse_dev *fuse_dev_alloc(struct fuse_conn *fc);
|
||||||
|
void fuse_dev_free(struct fuse_dev *fud);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Add connection to control filesystem
|
* Add connection to control filesystem
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -362,8 +362,8 @@ static void fuse_send_destroy(struct fuse_conn *fc)
|
||||||
if (req && fc->conn_init) {
|
if (req && fc->conn_init) {
|
||||||
fc->destroy_req = NULL;
|
fc->destroy_req = NULL;
|
||||||
req->in.h.opcode = FUSE_DESTROY;
|
req->in.h.opcode = FUSE_DESTROY;
|
||||||
req->force = 1;
|
__set_bit(FR_FORCE, &req->flags);
|
||||||
req->background = 0;
|
__clear_bit(FR_BACKGROUND, &req->flags);
|
||||||
fuse_request_send(fc, req);
|
fuse_request_send(fc, req);
|
||||||
fuse_put_request(fc, req);
|
fuse_put_request(fc, req);
|
||||||
}
|
}
|
||||||
|
@ -567,30 +567,46 @@ static int fuse_show_options(struct seq_file *m, struct dentry *root)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void fuse_iqueue_init(struct fuse_iqueue *fiq)
|
||||||
|
{
|
||||||
|
memset(fiq, 0, sizeof(struct fuse_iqueue));
|
||||||
|
init_waitqueue_head(&fiq->waitq);
|
||||||
|
INIT_LIST_HEAD(&fiq->pending);
|
||||||
|
INIT_LIST_HEAD(&fiq->interrupts);
|
||||||
|
fiq->forget_list_tail = &fiq->forget_list_head;
|
||||||
|
fiq->connected = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void fuse_pqueue_init(struct fuse_pqueue *fpq)
|
||||||
|
{
|
||||||
|
memset(fpq, 0, sizeof(struct fuse_pqueue));
|
||||||
|
spin_lock_init(&fpq->lock);
|
||||||
|
INIT_LIST_HEAD(&fpq->processing);
|
||||||
|
INIT_LIST_HEAD(&fpq->io);
|
||||||
|
fpq->connected = 1;
|
||||||
|
}
|
||||||
|
|
||||||
void fuse_conn_init(struct fuse_conn *fc)
|
void fuse_conn_init(struct fuse_conn *fc)
|
||||||
{
|
{
|
||||||
memset(fc, 0, sizeof(*fc));
|
memset(fc, 0, sizeof(*fc));
|
||||||
spin_lock_init(&fc->lock);
|
spin_lock_init(&fc->lock);
|
||||||
init_rwsem(&fc->killsb);
|
init_rwsem(&fc->killsb);
|
||||||
atomic_set(&fc->count, 1);
|
atomic_set(&fc->count, 1);
|
||||||
init_waitqueue_head(&fc->waitq);
|
atomic_set(&fc->dev_count, 1);
|
||||||
init_waitqueue_head(&fc->blocked_waitq);
|
init_waitqueue_head(&fc->blocked_waitq);
|
||||||
init_waitqueue_head(&fc->reserved_req_waitq);
|
init_waitqueue_head(&fc->reserved_req_waitq);
|
||||||
INIT_LIST_HEAD(&fc->pending);
|
fuse_iqueue_init(&fc->iq);
|
||||||
INIT_LIST_HEAD(&fc->processing);
|
|
||||||
INIT_LIST_HEAD(&fc->io);
|
|
||||||
INIT_LIST_HEAD(&fc->interrupts);
|
|
||||||
INIT_LIST_HEAD(&fc->bg_queue);
|
INIT_LIST_HEAD(&fc->bg_queue);
|
||||||
INIT_LIST_HEAD(&fc->entry);
|
INIT_LIST_HEAD(&fc->entry);
|
||||||
fc->forget_list_tail = &fc->forget_list_head;
|
INIT_LIST_HEAD(&fc->devices);
|
||||||
atomic_set(&fc->num_waiting, 0);
|
atomic_set(&fc->num_waiting, 0);
|
||||||
fc->max_background = FUSE_DEFAULT_MAX_BACKGROUND;
|
fc->max_background = FUSE_DEFAULT_MAX_BACKGROUND;
|
||||||
fc->congestion_threshold = FUSE_DEFAULT_CONGESTION_THRESHOLD;
|
fc->congestion_threshold = FUSE_DEFAULT_CONGESTION_THRESHOLD;
|
||||||
fc->khctr = 0;
|
fc->khctr = 0;
|
||||||
fc->polled_files = RB_ROOT;
|
fc->polled_files = RB_ROOT;
|
||||||
fc->reqctr = 0;
|
|
||||||
fc->blocked = 0;
|
fc->blocked = 0;
|
||||||
fc->initialized = 0;
|
fc->initialized = 0;
|
||||||
|
fc->connected = 1;
|
||||||
fc->attr_version = 1;
|
fc->attr_version = 1;
|
||||||
get_random_bytes(&fc->scramble_key, sizeof(fc->scramble_key));
|
get_random_bytes(&fc->scramble_key, sizeof(fc->scramble_key));
|
||||||
}
|
}
|
||||||
|
@ -930,6 +946,7 @@ static void fuse_send_init(struct fuse_conn *fc, struct fuse_req *req)
|
||||||
|
|
||||||
static void fuse_free_conn(struct fuse_conn *fc)
|
static void fuse_free_conn(struct fuse_conn *fc)
|
||||||
{
|
{
|
||||||
|
WARN_ON(!list_empty(&fc->devices));
|
||||||
kfree_rcu(fc, rcu);
|
kfree_rcu(fc, rcu);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -975,8 +992,42 @@ static int fuse_bdi_init(struct fuse_conn *fc, struct super_block *sb)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct fuse_dev *fuse_dev_alloc(struct fuse_conn *fc)
|
||||||
|
{
|
||||||
|
struct fuse_dev *fud;
|
||||||
|
|
||||||
|
fud = kzalloc(sizeof(struct fuse_dev), GFP_KERNEL);
|
||||||
|
if (fud) {
|
||||||
|
fud->fc = fuse_conn_get(fc);
|
||||||
|
fuse_pqueue_init(&fud->pq);
|
||||||
|
|
||||||
|
spin_lock(&fc->lock);
|
||||||
|
list_add_tail(&fud->entry, &fc->devices);
|
||||||
|
spin_unlock(&fc->lock);
|
||||||
|
}
|
||||||
|
|
||||||
|
return fud;
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL_GPL(fuse_dev_alloc);
|
||||||
|
|
||||||
|
void fuse_dev_free(struct fuse_dev *fud)
|
||||||
|
{
|
||||||
|
struct fuse_conn *fc = fud->fc;
|
||||||
|
|
||||||
|
if (fc) {
|
||||||
|
spin_lock(&fc->lock);
|
||||||
|
list_del(&fud->entry);
|
||||||
|
spin_unlock(&fc->lock);
|
||||||
|
|
||||||
|
fuse_conn_put(fc);
|
||||||
|
}
|
||||||
|
kfree(fud);
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL_GPL(fuse_dev_free);
|
||||||
|
|
||||||
static int fuse_fill_super(struct super_block *sb, void *data, int silent)
|
static int fuse_fill_super(struct super_block *sb, void *data, int silent)
|
||||||
{
|
{
|
||||||
|
struct fuse_dev *fud;
|
||||||
struct fuse_conn *fc;
|
struct fuse_conn *fc;
|
||||||
struct inode *root;
|
struct inode *root;
|
||||||
struct fuse_mount_data d;
|
struct fuse_mount_data d;
|
||||||
|
@ -1026,12 +1077,17 @@ static int fuse_fill_super(struct super_block *sb, void *data, int silent)
|
||||||
goto err_fput;
|
goto err_fput;
|
||||||
|
|
||||||
fuse_conn_init(fc);
|
fuse_conn_init(fc);
|
||||||
|
fc->release = fuse_free_conn;
|
||||||
|
|
||||||
|
fud = fuse_dev_alloc(fc);
|
||||||
|
if (!fud)
|
||||||
|
goto err_put_conn;
|
||||||
|
|
||||||
fc->dev = sb->s_dev;
|
fc->dev = sb->s_dev;
|
||||||
fc->sb = sb;
|
fc->sb = sb;
|
||||||
err = fuse_bdi_init(fc, sb);
|
err = fuse_bdi_init(fc, sb);
|
||||||
if (err)
|
if (err)
|
||||||
goto err_put_conn;
|
goto err_dev_free;
|
||||||
|
|
||||||
sb->s_bdi = &fc->bdi;
|
sb->s_bdi = &fc->bdi;
|
||||||
|
|
||||||
|
@ -1040,7 +1096,6 @@ static int fuse_fill_super(struct super_block *sb, void *data, int silent)
|
||||||
fc->dont_mask = 1;
|
fc->dont_mask = 1;
|
||||||
sb->s_flags |= MS_POSIXACL;
|
sb->s_flags |= MS_POSIXACL;
|
||||||
|
|
||||||
fc->release = fuse_free_conn;
|
|
||||||
fc->flags = d.flags;
|
fc->flags = d.flags;
|
||||||
fc->user_id = d.user_id;
|
fc->user_id = d.user_id;
|
||||||
fc->group_id = d.group_id;
|
fc->group_id = d.group_id;
|
||||||
|
@ -1053,14 +1108,14 @@ static int fuse_fill_super(struct super_block *sb, void *data, int silent)
|
||||||
root = fuse_get_root_inode(sb, d.rootmode);
|
root = fuse_get_root_inode(sb, d.rootmode);
|
||||||
root_dentry = d_make_root(root);
|
root_dentry = d_make_root(root);
|
||||||
if (!root_dentry)
|
if (!root_dentry)
|
||||||
goto err_put_conn;
|
goto err_dev_free;
|
||||||
/* only now - we want root dentry with NULL ->d_op */
|
/* only now - we want root dentry with NULL ->d_op */
|
||||||
sb->s_d_op = &fuse_dentry_operations;
|
sb->s_d_op = &fuse_dentry_operations;
|
||||||
|
|
||||||
init_req = fuse_request_alloc(0);
|
init_req = fuse_request_alloc(0);
|
||||||
if (!init_req)
|
if (!init_req)
|
||||||
goto err_put_root;
|
goto err_put_root;
|
||||||
init_req->background = 1;
|
__set_bit(FR_BACKGROUND, &init_req->flags);
|
||||||
|
|
||||||
if (is_bdev) {
|
if (is_bdev) {
|
||||||
fc->destroy_req = fuse_request_alloc(0);
|
fc->destroy_req = fuse_request_alloc(0);
|
||||||
|
@ -1079,8 +1134,7 @@ static int fuse_fill_super(struct super_block *sb, void *data, int silent)
|
||||||
|
|
||||||
list_add_tail(&fc->entry, &fuse_conn_list);
|
list_add_tail(&fc->entry, &fuse_conn_list);
|
||||||
sb->s_root = root_dentry;
|
sb->s_root = root_dentry;
|
||||||
fc->connected = 1;
|
file->private_data = fud;
|
||||||
file->private_data = fuse_conn_get(fc);
|
|
||||||
mutex_unlock(&fuse_mutex);
|
mutex_unlock(&fuse_mutex);
|
||||||
/*
|
/*
|
||||||
* atomic_dec_and_test() in fput() provides the necessary
|
* atomic_dec_and_test() in fput() provides the necessary
|
||||||
|
@ -1099,6 +1153,8 @@ static int fuse_fill_super(struct super_block *sb, void *data, int silent)
|
||||||
fuse_request_free(init_req);
|
fuse_request_free(init_req);
|
||||||
err_put_root:
|
err_put_root:
|
||||||
dput(root_dentry);
|
dput(root_dentry);
|
||||||
|
err_dev_free:
|
||||||
|
fuse_dev_free(fud);
|
||||||
err_put_conn:
|
err_put_conn:
|
||||||
fuse_bdi_destroy(fc);
|
fuse_bdi_destroy(fc);
|
||||||
fuse_conn_put(fc);
|
fuse_conn_put(fc);
|
||||||
|
|
|
@ -755,4 +755,7 @@ struct fuse_notify_retrieve_in {
|
||||||
uint64_t dummy4;
|
uint64_t dummy4;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/* Device ioctls: */
|
||||||
|
#define FUSE_DEV_IOC_CLONE _IOR(229, 0, uint32_t)
|
||||||
|
|
||||||
#endif /* _LINUX_FUSE_H */
|
#endif /* _LINUX_FUSE_H */
|
||||||
|
|
Loading…
Reference in a new issue