diff options
author | Miklos Szeredi <miklos@szeredi.hu> | 2005-07-22 17:24:30 +0000 |
---|---|---|
committer | Miklos Szeredi <miklos@szeredi.hu> | 2005-07-22 17:24:30 +0000 |
commit | e3b830965749c516756f4c13588a1eb29e648ec2 (patch) | |
tree | 7ac513a4e3f5c843c77ae5575c9e855ed169fba2 /kernel | |
parent | 8d4d1b824173870c94f121416d2cf4704896787e (diff) | |
download | libfuse-e3b830965749c516756f4c13588a1eb29e648ec2.tar.gz |
added file locking
Diffstat (limited to 'kernel')
-rw-r--r-- | kernel/file.c | 121 | ||||
-rw-r--r-- | kernel/fuse_i.h | 2 | ||||
-rw-r--r-- | kernel/fuse_kernel.h | 19 | ||||
-rw-r--r-- | kernel/inode.c | 2 |
4 files changed, 141 insertions, 3 deletions
diff --git a/kernel/file.c b/kernel/file.c index f5e2c87..02dc9f0 100644 --- a/kernel/file.c +++ b/kernel/file.c @@ -606,6 +606,125 @@ static ssize_t fuse_direct_write(struct file *file, const char __user *buf, return res; } +static int default_getlk(struct file *file, struct file_lock *fl) +{ + struct file_lock *cfl = posix_test_lock(file, fl); + fl->fl_type = F_UNLCK; + if (cfl) + *fl = *cfl; + return 0; +} + +static void convert_file_lock(const struct file_lock *fl, + struct fuse_file_lock *ffl) +{ + ffl->start = fl->fl_start; + ffl->end = fl->fl_end; + ffl->owner = (unsigned long) fl->fl_owner; + ffl->pid = fl->fl_pid; + ffl->type = fl->fl_type; +} + +static int convert_fuse_file_lock(const struct fuse_file_lock *ffl, + struct file_lock *fl) +{ + if (ffl->start < 0 || ffl->end < 0 || ffl->end <= ffl->start) + return -EIO; + + if (ffl->type != F_UNLCK && ffl->type != F_RDLCK && + ffl->type != F_WRLCK) + return -EIO; + + fl->fl_start = ffl->start; + fl->fl_end = ffl->end; + fl->fl_owner = (fl_owner_t) (unsigned long) ffl->owner; + fl->fl_pid = ffl->pid; + fl->fl_type = ffl->type; + + return 0; +} + +static int fuse_getlk(struct file *file, struct file_lock *fl) +{ + struct inode *inode = file->f_dentry->d_inode; + struct fuse_conn *fc = get_fuse_conn(inode); + struct fuse_req *req; + struct fuse_lk_in_out arg; + int err; + + if (fc->no_lk) + return default_getlk(file, fl); + + req = fuse_get_request(fc); + if (!req) + return -EINTR; + + memset(&arg, 0, sizeof(arg)); + convert_file_lock(fl, &arg.lk); + req->in.h.opcode = FUSE_GETLK; + req->in.h.nodeid = get_node_id(inode); + req->inode = inode; + req->in.numargs = 1; + req->in.args[0].size = sizeof(arg); + req->in.args[0].value = &arg; + req->out.numargs = 1; + req->out.args[0].size = sizeof(arg); + req->out.args[0].value = &arg; + request_send(fc, req); + err = req->out.h.error; + fuse_put_request(fc, req); + if (!err) + err = convert_fuse_file_lock(&arg.lk, fl); + else if (err == -ENOSYS) { + fc->no_lk = 1; + err = default_getlk(file, fl); + } + + return err; +} + +static int fuse_setlk(struct file *file, struct file_lock *fl) +{ + struct inode *inode = file->f_dentry->d_inode; + struct fuse_conn *fc = get_fuse_conn(inode); + struct fuse_req *req; + struct fuse_lk_in_out arg; + int err; + + if (fc->no_lk) + return posix_lock_file_wait(file, fl); + + req = fuse_get_request(fc); + if (!req) + return -EINTR; + + 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.nodeid = get_node_id(inode); + req->inode = inode; + req->in.numargs = 1; + req->in.args[0].size = sizeof(arg); + req->in.args[0].value = &arg; + request_send(fc, req); + err = req->out.h.error; + fuse_put_request(fc, req); + if (err == -ENOSYS) { + fc->no_lk = 1; + err = posix_lock_file_wait(file, fl); + } + + return err; +} + +static int fuse_file_lock(struct file *file, int cmd, struct file_lock *fl) +{ + if (cmd == F_GETLK) + return fuse_getlk(file, fl); + else + return fuse_setlk(file, fl); +} + #ifndef KERNEL_2_6 static ssize_t fuse_file_read(struct file *file, char __user *buf, size_t count, loff_t *ppos) @@ -657,6 +776,7 @@ static struct file_operations fuse_file_operations = { .flush = fuse_flush, .release = fuse_release, .fsync = fuse_fsync, + .lock = fuse_file_lock, #ifdef KERNEL_2_6 .sendfile = generic_file_sendfile, #endif @@ -670,6 +790,7 @@ static struct file_operations fuse_direct_io_file_operations = { .flush = fuse_flush, .release = fuse_release, .fsync = fuse_fsync, + .lock = fuse_file_lock, /* no mmap and sendfile */ }; diff --git a/kernel/fuse_i.h b/kernel/fuse_i.h index b9b29eb..6b7ba16 100644 --- a/kernel/fuse_i.h +++ b/kernel/fuse_i.h @@ -336,6 +336,8 @@ struct fuse_conn { /** Is removexattr not implemented by fs? */ unsigned no_removexattr : 1; + unsigned no_lk : 1; + #ifdef KERNEL_2_6 /** Backing dev info */ struct backing_dev_info bdi; diff --git a/kernel/fuse_kernel.h b/kernel/fuse_kernel.h index 104d31a..a470bed 100644 --- a/kernel/fuse_kernel.h +++ b/kernel/fuse_kernel.h @@ -14,7 +14,7 @@ #define FUSE_KERNEL_VERSION 7 /** Minor version number of this interface */ -#define FUSE_KERNEL_MINOR_VERSION 1 +#define FUSE_KERNEL_MINOR_VERSION 2 /** The node ID of the root inode */ #define FUSE_ROOT_ID 1 @@ -55,6 +55,14 @@ struct fuse_kstatfs { __u32 namelen; }; +struct fuse_file_lock { + __u64 start; + __u64 end; + __u64 owner; + __u32 pid; + __u32 type; +}; + #define FATTR_MODE (1 << 0) #define FATTR_UID (1 << 1) #define FATTR_GID (1 << 2) @@ -91,7 +99,10 @@ enum fuse_opcode { FUSE_OPENDIR = 27, FUSE_READDIR = 28, FUSE_RELEASEDIR = 29, - FUSE_FSYNCDIR = 30 + FUSE_FSYNCDIR = 30, + FUSE_GETLK = 31, + FUSE_SETLK = 32, + FUSE_SETLKW = 33 }; /* Conservative buffer size for the client */ @@ -214,6 +225,10 @@ struct fuse_getxattr_out { __u32 padding; }; +struct fuse_lk_in_out { + struct fuse_file_lock lk; +}; + struct fuse_init_in_out { __u32 major; __u32 minor; diff --git a/kernel/inode.c b/kernel/inode.c index 7717ef1..e256cd7 100644 --- a/kernel/inode.c +++ b/kernel/inode.c @@ -502,7 +502,7 @@ static struct fuse_conn *new_conn(void) fc->bdi.ra_pages = (VM_MAX_READAHEAD * 1024) / PAGE_CACHE_SIZE; fc->bdi.unplug_io_fn = default_unplug_io_fn; #endif - fc->reqctr = 1; + fc->reqctr = 0; } return fc; } |