-2005-09-02 Miklos Szeredi <miklos@szeredi.hu>
+2005-09-08 Miklos Szeredi <miklos@szeredi.hu>
+
+ * Revert lock and access operations. Postpone these until 2.5.
- * Don't call ACCESS on open. Will do this properly with atomic
- open/create
+2005-09-02 Miklos Szeredi <miklos@szeredi.hu>
* Fix compile warning on 2.6.13 and later
* Fix compilation on old kernels
-2005-08-25 Miklos Szeredi <miklos@szeredi.hu>
-
- * lib: add userspace side of ftruncate() method for experimentation
-
-2005-08-23 Miklos Szeredi <miklos@szeredi.hu>
-
- * lib: add userspace side of create() method for experimentation
-
2005-08-19 Miklos Szeredi <miklos@szeredi.hu>
* lib: always refresh directory contents after rewinddir() to
* Added missing symbols to versionscript (Joshua J. Berry)
- * Do not limit number of file locks being waited upon
-
* kernel: implement two flags, open can set: 'direct_io' and
'keep_cache'. These correspond exactly to mount options
'direct_io' and 'kernel_cache', but allow a per-open setting.
the respective open flag is set, otherwise the open flag is left
unmodified (so the filesystem can set it).
- * Add ACCESS operation. This is called from the access() system
- call if 'default_permissions' mount option is not given
-
- * Perform ACCESS operation in case of open(), if the file wasn't
- newly created
-
* lib (highlevel): make open method optional
2005-07-28 Miklos Szeredi <miklos@szeredi.hu>
2,147,483,648 operations, so most people won't care. Thanks to
Franco Broi for the report and testing.
- * Added file locking methods to kernel and low-level API.
-
2005-07-21 Miklos Szeredi <miklos@szeredi.hu>
* Don't change mtime/ctime/atime to local time on read/write.
- Low level (inode based) API added
- - File locking primitives added to kernel and low level API
-
- - Add 'access' method to kernel, and library APIs
-
- Allow 'direct_io' and 'keep_cache' options to be set on a
case-by-case basis on open.
void (*getattr)(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi);
void (*setattr)(fuse_req_t req, fuse_ino_t ino, struct stat *attr,
int to_set, struct fuse_file_info *fi);
- void (*access) (fuse_req_t req, fuse_ino_t ino, int mask);
void (*readlink)(fuse_req_t req, fuse_ino_t ino);
void (*mknod) (fuse_req_t req, fuse_ino_t parent, const char *name,
mode_t mode, dev_t rdev);
fuse_ino_t newparent, const char *newname);
void (*link) (fuse_req_t req, fuse_ino_t ino, fuse_ino_t newparent,
const char *newname);
- void (*create) (fuse_req_t req, fuse_ino_t parent, const char *name,
- mode_t mode, struct fuse_file_info *fi);
void (*open) (fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi);
void (*read) (fuse_req_t req, fuse_ino_t ino, size_t size, off_t off,
struct fuse_file_info *fi);
size_t size);
void (*listxattr)(fuse_req_t req, fuse_ino_t ino, size_t size);
void (*removexattr)(fuse_req_t req, fuse_ino_t ino, const char *name);
- void (*getlk) (fuse_req_t req, fuse_ino_t ino,
- const struct fuse_lock_param *lk);
- void (*setlk) (fuse_req_t req, fuse_ino_t ino, int sleep,
- const struct fuse_lock_param *lk);
};
/* ------------------------------------------ */
/* forget */
int fuse_reply_none(fuse_req_t req);
-/* lookup, create, mknod, mkdir, symlink, link */
+/* lookup, mknod, mkdir, symlink, link */
int fuse_reply_entry(fuse_req_t req, const struct fuse_entry_param *e);
-/* create */
-int fuse_reply_create(fuse_req_t req, const struct fuse_entry_param *e,
- const struct fuse_file_info *fi);
-
/* getattr, setattr */
int fuse_reply_attr(fuse_req_t req, const struct stat *attr,
double attr_timeout);
/* getxattr, listxattr */
int fuse_reply_xattr(fuse_req_t req, size_t count);
-/* getlk */
-int fuse_reply_getlk(fuse_req_t req, const struct fuse_lock_param *lk);
-
/* ------------------------------------------ */
/* return the size of a directory entry */
else
fuse_request_free(req);
- if (!req->unaccounted) {
- /* If we are in debt decrease that first */
- if (fc->outstanding_debt)
- fc->outstanding_debt--;
- else
- up(&fc->outstanding_sem);
- }
+ /* If we are in debt decrease that first */
+ if (fc->outstanding_debt)
+ fc->outstanding_debt--;
+ else
+ up(&fc->outstanding_sem);
spin_unlock(&fuse_lock);
}
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 && !req->unaccounted) {
+ if (!req->preallocated) {
/* If request is not preallocated (either FORGET or
- RELEASE), and is not unaccounted (SETLKW),
- then still decrease outstanding_sem, so
+ RELEASE), 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()
unsigned long nsec)
{
struct timespec ts = {sec, nsec};
- return jiffies + ((sec || nsec) ? timespec_to_jiffies(&ts) : 0) - 1;
+ return jiffies + timespec_to_jiffies(&ts);
}
static void fuse_lookup_init(struct fuse_req *req, struct inode *dir,
return fuse_do_getattr(inode);
}
-#ifdef KERNEL_2_6
-static int fuse_access(struct inode *inode, int mask)
-{
- struct fuse_conn *fc = get_fuse_conn(inode);
- struct fuse_req *req;
- struct fuse_access_in inarg;
- int err;
-
- if (fc->no_access)
- return 0;
-
- req = fuse_get_request(fc);
- if (!req)
- return -EINTR;
-
- memset(&inarg, 0, sizeof(inarg));
- inarg.mask = mask;
- req->in.h.opcode = FUSE_ACCESS;
- req->in.h.nodeid = get_node_id(inode);
- req->inode = inode;
- req->in.numargs = 1;
- req->in.args[0].size = sizeof(inarg);
- req->in.args[0].value = &inarg;
- request_send(fc, req);
- err = req->out.h.error;
- fuse_put_request(fc, req);
- if (err == -ENOSYS) {
- fc->no_access = 1;
- err = 0;
- }
- return err;
-}
-#endif
-
static int fuse_permission(struct inode *inode, int mask, struct nameidata *nd)
{
struct fuse_conn *fc = get_fuse_conn(inode);
- int err;
if (!fuse_allow_task(fc, current))
return -EACCES;
else if (fc->flags & FUSE_DEFAULT_PERMISSIONS) {
#ifdef KERNEL_2_6_10_PLUS
- err = generic_permission(inode, mask, NULL);
+ int err = generic_permission(inode, mask, NULL);
#else
- err = vfs_permission(inode, mask);
+ int err = vfs_permission(inode, mask);
#endif
/* If permission is denied, try to refresh file
This is actually not so grave, since the user can
simply keep access to the file/directory anyway by
keeping it open... */
+
+ return err;
} else {
int mode = inode->i_mode;
if ((mask & MAY_WRITE) && IS_RDONLY(inode) &&
return -EROFS;
if ((mask & MAY_EXEC) && !S_ISDIR(mode) && !(mode & S_IXUGO))
return -EACCES;
-
- err = 0;
-#ifdef KERNEL_2_6
- if (nd && (nd->flags & LOOKUP_ACCESS))
- err = fuse_access(inode, mask);
-#endif
+ return 0;
}
- return err;
}
static int parse_dirfile(char *buf, size_t nbytes, struct file *file,
} else {
if (!isdir && (outarg.open_flags & FOPEN_DIRECT_IO))
file->f_op = &fuse_direct_io_file_operations;
- if (!(outarg.open_flags & FOPEN_KEEP_CACHE)) {
+ if (!(outarg.open_flags & FOPEN_KEEP_CACHE))
#ifdef KERNEL_2_6
invalidate_inode_pages(inode->i_mapping);
#else
invalidate_inode_pages(inode);
#endif
- }
ff->fh = outarg.fh;
file->private_data = ff;
}
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, int sleep)
-{
- 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 -ENOSYS;
-
- 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 = 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;
-
- 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 {
-#ifdef KERNEL_2_6
- int err = fuse_setlk(file, fl, fl->fl_flags & FL_SLEEP);
-#else
- int err = fuse_setlk(file, fl,
- cmd == F_SETLKW || cmd == F_SETLKW64);
-#endif
-#ifdef KERNEL_2_6_9_PLUS
- if (err == -ENOSYS)
- err = posix_lock_file_wait(file, fl);
-#else
- if (err == -ENOSYS)
- err = 0;
-#endif
- return err;
- }
-}
-
#ifndef KERNEL_2_6
static ssize_t fuse_file_read(struct file *file, char __user *buf,
size_t count, loff_t *ppos)
.flush = fuse_flush,
.release = fuse_release,
.fsync = fuse_fsync,
- .lock = fuse_file_lock,
#ifdef KERNEL_2_6
.sendfile = generic_file_sendfile,
#endif
.flush = fuse_flush,
.release = fuse_release,
.fsync = fuse_fsync,
- .lock = fuse_file_lock,
/* no mmap and sendfile */
};
/** 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;
/** Is removexattr not implemented by fs? */
unsigned no_removexattr : 1;
- /** Are file locking primitives not implemented by fs? */
- unsigned no_lk : 1;
-
- /** Is access not implemented by fs? */
- unsigned no_access : 1;
-
#ifdef KERNEL_2_6
/** Backing dev info */
struct backing_dev_info bdi;
__u32 namelen;
};
-struct fuse_file_lock {
- __u64 start;
- __u64 end;
- __u64 owner;
- __u32 pid;
- __u32 type;
-};
-
-/** Valid attribute mask used in the SETATTR request */
#define FATTR_MODE (1 << 0)
#define FATTR_UID (1 << 1)
#define FATTR_GID (1 << 2)
FUSE_OPENDIR = 27,
FUSE_READDIR = 28,
FUSE_RELEASEDIR = 29,
- FUSE_FSYNCDIR = 30,
- FUSE_GETLK = 31,
- FUSE_SETLK = 32,
- FUSE_SETLKW = 33,
- FUSE_ACCESS = 34,
- FUSE_CREATE = 35,
- FUSE_FSETATTR = 36
+ FUSE_FSYNCDIR = 30
};
/* Conservative buffer size for the client */
struct fuse_attr attr;
};
-struct fuse_fsetattr_in {
- __u64 fh;
- struct fuse_setattr_in setattr;
-};
-
struct fuse_open_in {
__u32 flags;
- __u32 mode;
+ __u32 padding;
};
struct fuse_open_out {
__u32 padding;
};
-struct fuse_lk_in_out {
- struct fuse_file_lock lk;
-};
-
-struct fuse_access_in {
- __u32 mask;
- __u32 padding;
-};
-
struct fuse_init_in_out {
__u32 major;
__u32 minor;
reply_err(req, err);
}
-static void fuse_access(fuse_req_t req, fuse_ino_t ino, int mask)
-{
- struct fuse *f = req_fuse_prepare(req);
- char *path;
- int err;
-
- err = -ENOENT;
- pthread_rwlock_rdlock(&f->tree_lock);
- path = get_path(f, ino);
- if (path != NULL) {
- err = -ENOSYS;
- if (f->op.access)
- err = f->op.access(path, mask);
- free(path);
- }
- pthread_rwlock_unlock(&f->tree_lock);
- reply_err(req, err);
-}
-
static void fuse_readlink(fuse_req_t req, fuse_ino_t ino)
{
struct fuse *f = req_fuse_prepare(req);
reply_entry(req, &e, err);
}
-static void fuse_create(fuse_req_t req, fuse_ino_t parent, const char *name,
- mode_t mode, struct fuse_file_info *fi)
-{
- struct fuse *f = req_fuse_prepare(req);
- struct fuse_entry_param e;
- char *path;
- int opened = 0;
- int err;
-
- err = -ENOENT;
- pthread_rwlock_rdlock(&f->tree_lock);
- path = get_path_name(f, parent, name);
- if (path != NULL) {
- err = -ENOSYS;
- if (f->op.create && f->op.getattr) {
- int oerr = f->op.create(path, mode, fi);
- if (!oerr)
- opened = 1;
-
- if (f->flags & FUSE_DEBUG) {
- if (opened)
- printf("CREATE[%lu] flags: 0x%x %s\n", fi->fh, fi->flags, path);
- else
- printf("LOOKUP(CREATE) %s\n", path);
- fflush(stdout);
- }
-
- err = lookup_path(f, parent, name, path, &e);
- if (err) {
- if (f->op.release && opened)
- f->op.release(path, fi);
- } else if (opened != (S_ISREG(e.attr.st_mode) != 0)) {
- err = oerr ? oerr : -EIO;
- if (f->op.release && opened)
- f->op.release(path, fi);
- forget_node(f, e.ino, 1);
- }
- }
- }
-
- if (!err) {
- if (f->flags & FUSE_DIRECT_IO)
- fi->direct_io = 1;
- if (f->flags & FUSE_KERNEL_CACHE)
- fi->keep_cache = 1;
-
- pthread_mutex_lock(&f->lock);
- if (fuse_reply_create(req, &e, fi) == -ENOENT) {
- /* The open syscall was interrupted, so it must be cancelled */
- if(f->op.release && opened)
- f->op.release(path, fi);
- forget_node(f, e.ino, 1);
- } else {
- struct node *node = get_node(f, e.ino);
- node->open_count ++;
- }
- pthread_mutex_unlock(&f->lock);
- } else
- reply_err(req, err);
-
- if (path)
- free(path);
- pthread_rwlock_unlock(&f->tree_lock);
-}
-
static void fuse_open(fuse_req_t req, fuse_ino_t ino,
struct fuse_file_info *fi)
{
.forget = fuse_forget,
.getattr = fuse_getattr,
.setattr = fuse_setattr,
- .access = fuse_access,
.readlink = fuse_readlink,
.mknod = fuse_mknod,
.mkdir = fuse_mkdir,
.symlink = fuse_symlink,
.rename = fuse_rename,
.link = fuse_link,
- .create = fuse_create,
.open = fuse_open,
.read = fuse_read,
.write = fuse_write,
case FUSE_READDIR: return "READDIR";
case FUSE_RELEASEDIR: return "RELEASEDIR";
case FUSE_FSYNCDIR: return "FSYNCDIR";
- case FUSE_GETLK: return "GETLK";
- case FUSE_SETLK: return "SETLK";
- case FUSE_SETLKW: return "SETLKW";
- case FUSE_ACCESS: return "ACCESS";
- case FUSE_CREATE: return "CREATE";
- case FUSE_FSETATTR: return "FSETATTR";
default: return "???";
}
}
#endif
}
-static void convert_file_lock(const struct fuse_file_lock *ffl,
- struct fuse_lock_param *lk)
-{
- lk->type = ffl->type;
- lk->start = ffl->start;
- lk->end = ffl->end;
- lk->owner = ffl->owner;
- lk->pid = ffl->pid;
-}
-
-static void convert_lock_param(const struct fuse_lock_param *lk,
- struct fuse_file_lock *ffl)
-{
- ffl->type = lk->type;
- ffl->start = lk->start;
- ffl->end = lk->end;
- ffl->owner = lk->owner;
- ffl->pid = lk->pid;
-}
-
static size_t iov_length(const struct iovec *iov, size_t count)
{
size_t seg;
return send_reply_ok(req, &arg, sizeof(arg));
}
-int fuse_reply_getlk(fuse_req_t req, const struct fuse_lock_param *lk)
-{
- struct fuse_lk_in_out arg;
-
- memset(&arg, 0, sizeof(arg));
- convert_lock_param(lk, &arg.lk);
-
- return send_reply_ok(req, &arg, sizeof(arg));
-}
-
static void do_lookup(fuse_req_t req, fuse_ino_t nodeid, char *name)
{
if (req->f->op.lookup)
fuse_reply_err(req, ENOSYS);
}
-static void do_fsetattr(fuse_req_t req, fuse_ino_t nodeid,
- struct fuse_fsetattr_in *arg)
-{
- struct fuse_file_info fi;
-
- memset(&fi, 0, sizeof(fi));
- fi.fh = arg->fh;
- do_setattr(req, nodeid, &arg->setattr, &fi);
-}
-
-static void do_access(fuse_req_t req, fuse_ino_t nodeid,
- struct fuse_access_in *arg)
-{
- if (req->f->op.access)
- req->f->op.access(req, nodeid, arg->mask);
- else
- fuse_reply_err(req, ENOSYS);
-}
static void do_readlink(fuse_req_t req, fuse_ino_t nodeid)
{
if (req->f->op.readlink)
fuse_reply_err(req, ENOSYS);
}
-static void do_create(fuse_req_t req, fuse_ino_t nodeid,
- struct fuse_open_in *arg)
-{
- if (req->f->op.create) {
- struct fuse_file_info fi;
-
- memset(&fi, 0, sizeof(fi));
- fi.flags = arg->flags;
-
- req->f->op.create(req, nodeid, PARAM(arg), arg->mode, &fi);
- } else
- fuse_reply_err(req, ENOSYS);
-}
-
static void do_open(fuse_req_t req, fuse_ino_t nodeid,
struct fuse_open_in *arg)
{
fuse_reply_err(req, ENOSYS);
}
-static void do_getlk(fuse_req_t req, fuse_ino_t nodeid,
- struct fuse_lk_in_out *arg)
-{
- if (req->f->op.getlk) {
- struct fuse_lock_param lk;
-
- memset(&lk, 0, sizeof(lk));
- convert_file_lock(&arg->lk, &lk);
- req->f->op.getlk(req, nodeid, &lk);
- } else
- fuse_reply_err(req, ENOSYS);
-}
-
-static void do_setlk(fuse_req_t req, fuse_ino_t nodeid, int issleep,
- struct fuse_lk_in_out *arg)
-{
- if (req->f->op.setlk) {
- struct fuse_lock_param lk;
-
- memset(&lk, 0, sizeof(lk));
- convert_file_lock(&arg->lk, &lk);
- req->f->op.setlk(req, nodeid, issleep, &lk);
- } else
- fuse_reply_err(req, ENOSYS);
-}
-
static void do_init(fuse_req_t req, struct fuse_init_in_out *arg)
{
struct fuse_init_in_out outarg;
do_setattr(req, in->nodeid, (struct fuse_setattr_in *) inarg, NULL);
break;
- case FUSE_FSETATTR:
- do_fsetattr(req, in->nodeid, (struct fuse_fsetattr_in *) inarg);
- break;
-
case FUSE_READLINK:
do_readlink(req, in->nodeid);
break;
do_fsyncdir(req, in->nodeid, (struct fuse_fsync_in *) inarg);
break;
- case FUSE_GETLK:
- do_getlk(req, in->nodeid, (struct fuse_lk_in_out *) inarg);
- break;
-
- case FUSE_SETLK:
- do_setlk(req, in->nodeid, 0, (struct fuse_lk_in_out *) inarg);
- break;
-
- case FUSE_SETLKW:
- do_setlk(req, in->nodeid, 1, (struct fuse_lk_in_out *) inarg);
- break;
-
- case FUSE_ACCESS:
- do_access(req, in->nodeid, (struct fuse_access_in *) inarg);
- break;
-
- case FUSE_CREATE:
- do_create(req, in->nodeid, (struct fuse_open_in *) inarg);
- break;
-
default:
fuse_reply_err(req, ENOSYS);
}