X-Git-Url: http://ftp.safe.ca/?a=blobdiff_plain;f=fs%2Ffuse%2Ffuse_i.h;h=69c7750d55b8e59cfd95a0322f45557a74c0fdfe;hb=e60d07b6cd38a7afb85f2cf51aebcb3359b63819;hp=c4e8c3b479821428607d7c91a4df6a03ce56d947;hpb=31d40d74b402a6fa18a006fb3745f64609f35b77;p=safe%2Fjmp%2Flinux-2.6 diff --git a/fs/fuse/fuse_i.h b/fs/fuse/fuse_i.h index c4e8c3b..69c7750 100644 --- a/fs/fuse/fuse_i.h +++ b/fs/fuse/fuse_i.h @@ -1,6 +1,6 @@ /* FUSE: Filesystem in Userspace - Copyright (C) 2001-2005 Miklos Szeredi + Copyright (C) 2001-2006 Miklos Szeredi This program can be distributed under the terms of the GNU GPL. See the file COPYING. @@ -8,18 +8,25 @@ #include #include +#include #include #include #include #include #include -#include +#include /** Max number of pages that can be used in a single read request */ #define FUSE_MAX_PAGES_PER_REQ 32 -/** If more requests are outstanding, then the operation will block */ -#define FUSE_MAX_OUTSTANDING 10 +/** Maximum number of outstanding background requests */ +#define FUSE_MAX_BACKGROUND 10 + +/** It could be as large as PATH_MAX, but would that have any uses? */ +#define FUSE_NAME_MAX 1024 + +/** Number of dentries for each connection in the control filesystem */ +#define FUSE_CTL_NUM_DENTRIES 3 /** If the FUSE_DEFAULT_PERMISSIONS flag is given, the filesystem module will check permissions based on the file mode. Otherwise no @@ -30,6 +37,11 @@ doing the mount will be allowed to access the filesystem */ #define FUSE_ALLOW_OTHER (1 << 1) +/** List of active connections */ +extern struct list_head fuse_conn_list; + +/** Global mutex protecting fuse_conn_list and the control filesystem */ +extern struct mutex fuse_mutex; /** FUSE inode */ struct fuse_inode { @@ -47,13 +59,13 @@ struct fuse_inode { struct fuse_req *forget_req; /** Time in jiffies until the file attributes are valid */ - unsigned long i_time; + u64 i_time; }; /** FUSE specific file data */ struct fuse_file { /** Request reserved for flush and release */ - struct fuse_req *release_req; + struct fuse_req *reserved_req; /** File handle used by userspace */ u64 fh; @@ -91,6 +103,11 @@ struct fuse_out { /** Header returned from userspace */ struct fuse_out_header h; + /* + * The following bitfields are not changed during the request + * processing + */ + /** Last argument is variable length (can be shorter than arg->size) */ unsigned argvar:1; @@ -108,43 +125,64 @@ struct fuse_out { struct fuse_arg args[3]; }; -struct fuse_req; +/** 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 +}; + struct fuse_conn; /** * A request to the client */ struct fuse_req { - /** This can be on either unused_list, pending or processing - lists in fuse_conn */ + /** This can be on either pending processing or io lists in + fuse_conn */ struct list_head list; - /** Entry on the background list */ - struct list_head bg_entry; + /** Entry on the interrupts list */ + struct list_head intr_entry; /** refcount */ atomic_t count; + /** Unique ID for the interrupt request */ + u64 intr_unique; + + /* + * The following bitfields are either set once before the + * request is queued or setting/clearing them is protected by + * fuse_conn->lock + */ + /** True if the request has reply */ unsigned isreply:1; - /** The request is preallocated */ - unsigned preallocated:1; + /** Force sending of the request even if interrupted */ + unsigned force:1; - /** The request was interrupted */ - unsigned interrupted: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 has been sent to userspace */ - unsigned sent:1; + /** Request is counted as "waiting" */ + unsigned waiting:1; - /** The request is finished */ - unsigned finished:1; + /** State of the request */ + enum fuse_req_state state; /** The request input */ struct fuse_in in; @@ -159,7 +197,10 @@ struct fuse_req { union { struct fuse_forget_in forget_in; struct fuse_release_in release_in; - struct fuse_init_in_out init_in_out; + struct fuse_init_in init_in; + struct fuse_init_out init_out; + struct fuse_read_in read_in; + struct fuse_lk_in lk_in; } misc; /** page vector */ @@ -171,14 +212,20 @@ struct fuse_req { /** offset of data on first page */ unsigned page_offset; - /** Inode used in the request */ - struct inode *inode; - - /** Second inode used in the request (or NULL) */ - struct inode *inode2; - /** File used in the request (or NULL) */ struct file *file; + + /** vfsmount used in release */ + struct vfsmount *vfsmount; + + /** dentry used in release */ + struct dentry *dentry; + + /** Request completion callback */ + void (*end)(struct fuse_conn *, struct fuse_req *); + + /** Request is stolen from fuse_file->reserved_req */ + struct file *stolen_file; }; /** @@ -189,8 +236,11 @@ struct fuse_req { * unmounted. */ struct fuse_conn { - /** Reference count */ - int count; + /** Lock protecting accessess to members of this structure */ + spinlock_t lock; + + /** Refcount */ + atomic_t count; /** The user id for this mount */ uid_t user_id; @@ -216,35 +266,43 @@ struct fuse_conn { /** The list of requests being processed */ struct list_head processing; - /** Requests put in the background (RELEASE or any other - interrupted request) */ - struct list_head background; + /** The list of requests under I/O */ + struct list_head io; - /** Controls the maximum number of outstanding requests */ - struct semaphore outstanding_sem; + /** Number of requests currently in the background */ + unsigned num_background; - /** This counts the number of outstanding requests if - outstanding_sem would go negative */ - unsigned outstanding_debt; + /** Pending interrupts */ + struct list_head interrupts; - /** RW semaphore for exclusion with fuse_put_super() */ - struct rw_semaphore sbput_sem; + /** Flag indicating if connection is blocked. This will be + the case before the INIT reply is received, and if there + are too many outstading backgrounds requests */ + int blocked; - /** The list of unused requests */ - struct list_head unused_list; + /** waitq for blocked connection */ + wait_queue_head_t blocked_waitq; /** The next unique request id */ u64 reqctr; - /** Mount is active */ - unsigned mounted : 1; + /** Connection established, cleared on umount, connection + abort and device release */ + unsigned connected; - /** Connection established */ - unsigned connected : 1; - - /** Connection failed (version mismatch) */ + /** Connection failed (version mismatch). Cannot race with + setting other bitfields since it is only set once in INIT + reply, before any other request, and never cleared */ unsigned conn_error : 1; + /** Do readpages asynchronously? Only set in INIT */ + unsigned async_read : 1; + + /* + * The following bitfields are only for optimization purposes + * and hence races in setting them will not cause malfunction + */ + /** Is fsync not implemented by fs? */ unsigned no_fsync : 1; @@ -266,21 +324,49 @@ struct fuse_conn { /** Is removexattr not implemented by fs? */ unsigned no_removexattr : 1; + /** Are file locking primitives not implemented by fs? */ + unsigned no_lock : 1; + /** Is access not implemented by fs? */ unsigned no_access : 1; + /** Is create not implemented by fs? */ + unsigned no_create : 1; + + /** Is interrupt not implemented by fs? */ + unsigned no_interrupt : 1; + + /** The number of requests waiting for completion */ + atomic_t num_waiting; + + /** Negotiated minor version */ + unsigned minor; + /** Backing dev info */ struct backing_dev_info bdi; -}; -static inline struct fuse_conn **get_fuse_conn_super_p(struct super_block *sb) -{ - return (struct fuse_conn **) &sb->s_fs_info; -} + /** Entry on the fuse_conn_list */ + struct list_head entry; + + /** Unique ID */ + u64 id; + + /** Dentries in the control filesystem */ + struct dentry *ctl_dentry[FUSE_CTL_NUM_DENTRIES]; + + /** number of dentries used in the above array */ + int ctl_ndents; + + /** O_ASYNC requests */ + struct fasync_struct *fasync; + + /** Key for lock owner ID scrambling */ + u32 scramble_key[4]; +}; static inline struct fuse_conn *get_fuse_conn_super(struct super_block *sb) { - return *get_fuse_conn_super_p(sb); + return sb->s_fs_info; } static inline struct fuse_conn *get_fuse_conn(struct inode *inode) @@ -299,22 +385,7 @@ static inline u64 get_node_id(struct inode *inode) } /** Device operations */ -extern struct file_operations fuse_dev_operations; - -/** - * This is the single global spinlock which protects FUSE's structures - * - * The following data is protected by this lock: - * - * - the private_data field of the device file - * - the s_fs_info field of the super block - * - unused_list, pending, processing lists in fuse_conn - * - background list in fuse_conn - * - the unique request ID counter reqctr in fuse_conn - * - the sb (super_block) field in fuse_conn - * - the file (device file) field in fuse_conn - */ -extern spinlock_t fuse_lock; +extern const struct file_operations fuse_dev_operations; /** * Get a filled in inode @@ -329,17 +400,24 @@ void fuse_send_forget(struct fuse_conn *fc, struct fuse_req *req, unsigned long nodeid, u64 nlookup); /** - * Send READ or READDIR request + * Initialize READ or READDIR request */ -size_t fuse_send_read_common(struct fuse_req *req, struct file *file, - struct inode *inode, loff_t pos, size_t count, - int isdir); +void fuse_read_fill(struct fuse_req *req, struct file *file, + struct inode *inode, loff_t pos, size_t count, int opcode); /** * Send OPEN or OPENDIR request */ int fuse_open_common(struct inode *inode, struct file *file, int isdir); +struct fuse_file *fuse_file_alloc(void); +void fuse_file_free(struct fuse_file *ff); +void fuse_finish_open(struct inode *inode, struct file *file, + struct fuse_file *ff, struct fuse_open_out *outarg); + +/** */ +struct fuse_req *fuse_release_fill(struct fuse_file *ff, u64 nodeid, int flags, + int opcode); /** * Send RELEASE or RELEASEDIR request */ @@ -377,12 +455,6 @@ void fuse_init_symlink(struct inode *inode); void fuse_change_attributes(struct inode *inode, struct fuse_attr *attr); /** - * Check if the connection can be released, and if yes, then free the - * connection structure - */ -void fuse_release_conn(struct fuse_conn *fc); - -/** * Initialize the client device */ int fuse_dev_init(void); @@ -392,6 +464,9 @@ int fuse_dev_init(void); */ void fuse_dev_cleanup(void); +int fuse_ctl_init(void); +void fuse_ctl_cleanup(void); + /** * Allocate a request */ @@ -403,18 +478,18 @@ struct fuse_req *fuse_request_alloc(void); void fuse_request_free(struct fuse_req *req); /** - * Reinitialize a request, the preallocated flag is left unmodified + * Get a request, may fail with -ENOMEM */ -void fuse_reset_request(struct fuse_req *req); +struct fuse_req *fuse_get_req(struct fuse_conn *fc); /** - * Reserve a preallocated request + * Gets a requests for a file operation, always succeeds */ -struct fuse_req *fuse_get_request(struct fuse_conn *fc); +struct fuse_req *fuse_get_req_nofail(struct fuse_conn *fc, struct file *file); /** - * Decrement reference count of a request. If count goes to zero put - * on unused list (preallocated) or free request (not preallocated). + * Decrement reference count of a request. If count goes to zero free + * the request. */ void fuse_put_request(struct fuse_conn *fc, struct fuse_req *req); @@ -433,10 +508,8 @@ void request_send_noreply(struct fuse_conn *fc, struct fuse_req *req); */ void request_send_background(struct fuse_conn *fc, struct fuse_req *req); -/** - * Release inodes and file associated with background request - */ -void fuse_release_background(struct fuse_req *req); +/* Abort all requests */ +void fuse_abort_conn(struct fuse_conn *fc); /** * Get the attributes of a file @@ -449,6 +522,21 @@ int fuse_do_getattr(struct inode *inode); void fuse_invalidate_attr(struct inode *inode); /** - * Send the INIT message + * Acquire reference to fuse_conn + */ +struct fuse_conn *fuse_conn_get(struct fuse_conn *fc); + +/** + * Release reference to fuse_conn + */ +void fuse_conn_put(struct fuse_conn *fc); + +/** + * Add connection to control filesystem + */ +int fuse_ctl_add_conn(struct fuse_conn *fc); + +/** + * Remove connection from control filesystem */ -void fuse_send_init(struct fuse_conn *fc); +void fuse_ctl_remove_conn(struct fuse_conn *fc);