mirror of
https://github.com/libfuse/libfuse.git
synced 2024-11-27 06:04:27 +08:00
* The context is extended with a 'umask' field. The umask is sent
for mknod, mkdir and create requests by linux kernel version 2.6.31 or later, otherwise the umask is set to zero. Also introduce a new feature flag: FUSE_CAP_DONT_MASK. If the kernel supports this feature, then this flag will be set in conn->capable in the ->init() method. If the filesystem sets this flag in in conn->want, then the create modes will not be masked. * Add low level interfaces for lookup cache and attribute invalidation. This feature is available in linux kernels 2.6.31 or later. Patch by John Muir * Kernel interface version is now 7.12
This commit is contained in:
parent
5bd3ba41e5
commit
24b35c3d97
16
ChangeLog
16
ChangeLog
@ -1,3 +1,19 @@
|
||||
2009-07-02 Miklos Szeredi <miklos@szeredi.hu>
|
||||
|
||||
* The context is extended with a 'umask' field. The umask is sent
|
||||
for mknod, mkdir and create requests by linux kernel version
|
||||
2.6.31 or later, otherwise the umask is set to zero. Also
|
||||
introduce a new feature flag: FUSE_CAP_DONT_MASK. If the kernel
|
||||
supports this feature, then this flag will be set in conn->capable
|
||||
in the ->init() method. If the filesystem sets this flag in in
|
||||
conn->want, then the create modes will not be masked.
|
||||
|
||||
* Add low level interfaces for lookup cache and attribute
|
||||
invalidation. This feature is available in linux kernels 2.6.31
|
||||
or later. Patch by John Muir
|
||||
|
||||
* Kernel interface version is now 7.12
|
||||
|
||||
2009-06-19 Miklos Szeredi <miklos@szeredi.hu>
|
||||
|
||||
* Add fuse_getgroups (high level lib) and fuse_req_getgroups (low
|
||||
|
@ -518,6 +518,9 @@ struct fuse_context {
|
||||
|
||||
/** Private filesystem data */
|
||||
void *private_data;
|
||||
|
||||
/** Umask of the calling process (introduced in version 2.8) */
|
||||
mode_t umask;
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -88,12 +88,14 @@ struct fuse_file_info {
|
||||
* FUSE_CAP_ATOMIC_O_TRUNC: filesystem handles the O_TRUNC open flag
|
||||
* FUSE_CAP_EXPORT_SUPPORT: filesystem handles lookups of "." and ".."
|
||||
* FUSE_CAP_BIG_WRITES: filesystem can handle write size larger than 4kB
|
||||
* FUSE_CAP_DONT_MASK: don't apply umask to file mode on create operations
|
||||
*/
|
||||
#define FUSE_CAP_ASYNC_READ (1 << 0)
|
||||
#define FUSE_CAP_POSIX_LOCKS (1 << 1)
|
||||
#define FUSE_CAP_ATOMIC_O_TRUNC (1 << 3)
|
||||
#define FUSE_CAP_EXPORT_SUPPORT (1 << 4)
|
||||
#define FUSE_CAP_BIG_WRITES (1 << 5)
|
||||
#define FUSE_CAP_DONT_MASK (1 << 6)
|
||||
|
||||
/**
|
||||
* Ioctl flags
|
||||
|
@ -51,6 +51,11 @@
|
||||
* - add IOCTL message
|
||||
* - add unsolicited notification support
|
||||
* - add POLL message and NOTIFY_POLL notification
|
||||
*
|
||||
* 7.12
|
||||
* - add umask flag to input argument of open, mknod and mkdir
|
||||
* - add notification messages for invalidation of inodes and
|
||||
* directory entries
|
||||
*/
|
||||
|
||||
#ifndef _LINUX_FUSE_H
|
||||
@ -58,6 +63,7 @@
|
||||
|
||||
#include <sys/types.h>
|
||||
#define __u64 uint64_t
|
||||
#define __s64 int64_t
|
||||
#define __u32 uint32_t
|
||||
#define __s32 int32_t
|
||||
|
||||
@ -65,7 +71,7 @@
|
||||
#define FUSE_KERNEL_VERSION 7
|
||||
|
||||
/** Minor version number of this interface */
|
||||
#define FUSE_KERNEL_MINOR_VERSION 11
|
||||
#define FUSE_KERNEL_MINOR_VERSION 12
|
||||
|
||||
/** The node ID of the root inode */
|
||||
#define FUSE_ROOT_ID 1
|
||||
@ -141,6 +147,7 @@ struct fuse_file_lock {
|
||||
* INIT request/reply flags
|
||||
*
|
||||
* FUSE_EXPORT_SUPPORT: filesystem handles lookups of "." and ".."
|
||||
* FUSE_DONT_MASK: don't apply umask to file mode on create operations
|
||||
*/
|
||||
#define FUSE_ASYNC_READ (1 << 0)
|
||||
#define FUSE_POSIX_LOCKS (1 << 1)
|
||||
@ -148,6 +155,7 @@ struct fuse_file_lock {
|
||||
#define FUSE_ATOMIC_O_TRUNC (1 << 3)
|
||||
#define FUSE_EXPORT_SUPPORT (1 << 4)
|
||||
#define FUSE_BIG_WRITES (1 << 5)
|
||||
#define FUSE_DONT_MASK (1 << 6)
|
||||
|
||||
/**
|
||||
* CUSE INIT request/reply flags
|
||||
@ -253,6 +261,8 @@ enum fuse_opcode {
|
||||
|
||||
enum fuse_notify_code {
|
||||
FUSE_NOTIFY_POLL = 1,
|
||||
FUSE_NOTIFY_INVAL_INODE = 2,
|
||||
FUSE_NOTIFY_INVAL_ENTRY = 3,
|
||||
FUSE_NOTIFY_CODE_MAX,
|
||||
};
|
||||
|
||||
@ -291,14 +301,18 @@ struct fuse_attr_out {
|
||||
struct fuse_attr attr;
|
||||
};
|
||||
|
||||
#define FUSE_COMPAT_MKNOD_IN_SIZE 8
|
||||
|
||||
struct fuse_mknod_in {
|
||||
__u32 mode;
|
||||
__u32 rdev;
|
||||
__u32 umask;
|
||||
__u32 padding;
|
||||
};
|
||||
|
||||
struct fuse_mkdir_in {
|
||||
__u32 mode;
|
||||
__u32 padding;
|
||||
__u32 umask;
|
||||
};
|
||||
|
||||
struct fuse_rename_in {
|
||||
@ -329,8 +343,15 @@ struct fuse_setattr_in {
|
||||
};
|
||||
|
||||
struct fuse_open_in {
|
||||
__u32 flags;
|
||||
__u32 unused;
|
||||
};
|
||||
|
||||
struct fuse_create_in {
|
||||
__u32 flags;
|
||||
__u32 mode;
|
||||
__u32 umask;
|
||||
__u32 padding;
|
||||
};
|
||||
|
||||
struct fuse_open_out {
|
||||
@ -537,4 +558,16 @@ struct fuse_dirent {
|
||||
#define FUSE_DIRENT_SIZE(d) \
|
||||
FUSE_DIRENT_ALIGN(FUSE_NAME_OFFSET + (d)->namelen)
|
||||
|
||||
struct fuse_notify_inval_inode_out {
|
||||
__u64 ino;
|
||||
__s64 off;
|
||||
__s64 len;
|
||||
};
|
||||
|
||||
struct fuse_notify_inval_entry_out {
|
||||
__u64 parent;
|
||||
__u32 namelen;
|
||||
__u32 padding;
|
||||
};
|
||||
|
||||
#endif /* _LINUX_FUSE_H */
|
||||
|
@ -109,6 +109,9 @@ struct fuse_ctx {
|
||||
|
||||
/** Thread ID of the calling process */
|
||||
pid_t pid;
|
||||
|
||||
/** Umask of the calling process (introduced in version 2.8) */
|
||||
mode_t umask;
|
||||
};
|
||||
|
||||
/* 'to_set' flags in setattr */
|
||||
@ -1151,6 +1154,32 @@ int fuse_reply_poll(fuse_req_t req, unsigned revents);
|
||||
*/
|
||||
int fuse_lowlevel_notify_poll(struct fuse_pollhandle *ph);
|
||||
|
||||
/**
|
||||
* Notify to invalidate cache for an inode
|
||||
*
|
||||
* @param ch the channel through which to send the invalidation
|
||||
* @param ino the inode number
|
||||
* @param off the offset in the inode where to start invalidating
|
||||
* or negative to invalidate attributes only
|
||||
* @param len the amount of cache to invalidate or 0 for all
|
||||
* @return zero for success, -errno for failure
|
||||
*/
|
||||
int fuse_lowlevel_notify_inval_inode(struct fuse_chan *ch, fuse_ino_t ino,
|
||||
off_t off, off_t len);
|
||||
|
||||
/**
|
||||
* Notify to invalidate parent attributes and the dentry matching
|
||||
* parent/name
|
||||
*
|
||||
* @param ch the channel through which to send the invalidation
|
||||
* @param parent inode number
|
||||
* @param name file name
|
||||
* @param namelen strlen() of file name
|
||||
* @return zero for success, -errno for failure
|
||||
*/
|
||||
int fuse_lowlevel_notify_inval_entry(struct fuse_chan *ch, fuse_ino_t parent,
|
||||
const char *name, size_t namelen);
|
||||
|
||||
/* ----------------------------------------------------------- *
|
||||
* Utility functions *
|
||||
* ----------------------------------------------------------- */
|
||||
@ -1375,6 +1404,14 @@ void fuse_session_reset(struct fuse_session *se);
|
||||
*/
|
||||
int fuse_session_exited(struct fuse_session *se);
|
||||
|
||||
/**
|
||||
* Get the user data provided to the session
|
||||
*
|
||||
* @param se the session
|
||||
* @return the user data
|
||||
*/
|
||||
void *fuse_session_data(struct fuse_session *se);
|
||||
|
||||
/**
|
||||
* Enter a single threaded event loop
|
||||
*
|
||||
|
15
lib/fuse.c
15
lib/fuse.c
@ -1422,8 +1422,10 @@ int fuse_fs_create(struct fuse_fs *fs, const char *path, mode_t mode,
|
||||
int err;
|
||||
|
||||
if (fs->debug)
|
||||
fprintf(stderr, "create flags: 0x%x %s\n", fi->flags,
|
||||
path);
|
||||
fprintf(stderr,
|
||||
"create flags: 0x%x %s 0%o umask=0%03o\n",
|
||||
fi->flags, path, mode,
|
||||
fuse_get_context()->umask);
|
||||
|
||||
err = fs->op.create(path, mode, fi);
|
||||
|
||||
@ -1572,8 +1574,9 @@ int fuse_fs_mknod(struct fuse_fs *fs, const char *path, mode_t mode,
|
||||
fuse_get_context()->private_data = fs->user_data;
|
||||
if (fs->op.mknod) {
|
||||
if (fs->debug)
|
||||
fprintf(stderr, "mknod %s 0%o 0x%llx\n", path,
|
||||
mode, (unsigned long long) rdev);
|
||||
fprintf(stderr, "mknod %s 0%o 0x%llx umask=0%03o\n",
|
||||
path, mode, (unsigned long long) rdev,
|
||||
fuse_get_context()->umask);
|
||||
|
||||
return fs->op.mknod(path, mode, rdev);
|
||||
} else {
|
||||
@ -1586,7 +1589,8 @@ int fuse_fs_mkdir(struct fuse_fs *fs, const char *path, mode_t mode)
|
||||
fuse_get_context()->private_data = fs->user_data;
|
||||
if (fs->op.mkdir) {
|
||||
if (fs->debug)
|
||||
fprintf(stderr, "mkdir %s 0%o\n", path, mode);
|
||||
fprintf(stderr, "mkdir %s 0%o umask=0%03o\n",
|
||||
path, mode, fuse_get_context()->umask);
|
||||
|
||||
return fs->op.mkdir(path, mode);
|
||||
} else {
|
||||
@ -1909,6 +1913,7 @@ static struct fuse *req_fuse_prepare(fuse_req_t req)
|
||||
c->ctx.uid = ctx->uid;
|
||||
c->ctx.gid = ctx->gid;
|
||||
c->ctx.pid = ctx->pid;
|
||||
c->ctx.umask = ctx->umask;
|
||||
return c->ctx.fuse;
|
||||
}
|
||||
|
||||
|
@ -606,9 +606,15 @@ static void do_readlink(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
|
||||
static void do_mknod(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
|
||||
{
|
||||
struct fuse_mknod_in *arg = (struct fuse_mknod_in *) inarg;
|
||||
char *name = PARAM(arg);
|
||||
|
||||
if (req->f->conn.proto_minor >= 12)
|
||||
req->ctx.umask = arg->umask;
|
||||
else
|
||||
name = (char *) inarg + FUSE_COMPAT_MKNOD_IN_SIZE;
|
||||
|
||||
if (req->f->op.mknod)
|
||||
req->f->op.mknod(req, nodeid, PARAM(arg), arg->mode, arg->rdev);
|
||||
req->f->op.mknod(req, nodeid, name, arg->mode, arg->rdev);
|
||||
else
|
||||
fuse_reply_err(req, ENOSYS);
|
||||
}
|
||||
@ -617,6 +623,9 @@ static void do_mkdir(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
|
||||
{
|
||||
struct fuse_mkdir_in *arg = (struct fuse_mkdir_in *) inarg;
|
||||
|
||||
if (req->f->conn.proto_minor >= 12)
|
||||
req->ctx.umask = arg->umask;
|
||||
|
||||
if (req->f->op.mkdir)
|
||||
req->f->op.mkdir(req, nodeid, PARAM(arg), arg->mode);
|
||||
else
|
||||
@ -678,15 +687,21 @@ static void do_link(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
|
||||
|
||||
static void do_create(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
|
||||
{
|
||||
struct fuse_open_in *arg = (struct fuse_open_in *) inarg;
|
||||
struct fuse_create_in *arg = (struct fuse_create_in *) inarg;
|
||||
|
||||
if (req->f->op.create) {
|
||||
struct fuse_file_info fi;
|
||||
char *name = PARAM(arg);
|
||||
|
||||
memset(&fi, 0, sizeof(fi));
|
||||
fi.flags = arg->flags;
|
||||
|
||||
req->f->op.create(req, nodeid, PARAM(arg), arg->mode, &fi);
|
||||
if (req->f->conn.proto_minor >= 12)
|
||||
req->ctx.umask = arg->umask;
|
||||
else
|
||||
name = (char *) inarg + sizeof(struct fuse_open_in);
|
||||
|
||||
req->f->op.create(req, nodeid, name, arg->mode, &fi);
|
||||
} else
|
||||
fuse_reply_err(req, ENOSYS);
|
||||
}
|
||||
@ -1168,6 +1183,8 @@ static void do_init(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
|
||||
f->conn.capable |= FUSE_CAP_EXPORT_SUPPORT;
|
||||
if (arg->flags & FUSE_BIG_WRITES)
|
||||
f->conn.capable |= FUSE_CAP_BIG_WRITES;
|
||||
if (arg->flags & FUSE_DONT_MASK)
|
||||
f->conn.capable |= FUSE_CAP_DONT_MASK;
|
||||
} else {
|
||||
f->conn.async_read = 0;
|
||||
f->conn.max_readahead = 0;
|
||||
@ -1207,6 +1224,8 @@ static void do_init(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
|
||||
outarg.flags |= FUSE_EXPORT_SUPPORT;
|
||||
if (f->conn.want & FUSE_CAP_BIG_WRITES)
|
||||
outarg.flags |= FUSE_BIG_WRITES;
|
||||
if (f->conn.want & FUSE_CAP_DONT_MASK)
|
||||
outarg.flags |= FUSE_DONT_MASK;
|
||||
outarg.max_readahead = f->conn.max_readahead;
|
||||
outarg.max_write = f->conn.max_write;
|
||||
|
||||
@ -1270,6 +1289,56 @@ int fuse_lowlevel_notify_poll(struct fuse_pollhandle *ph)
|
||||
}
|
||||
}
|
||||
|
||||
int fuse_lowlevel_notify_inval_inode(struct fuse_chan *ch, fuse_ino_t ino,
|
||||
off_t off, off_t len)
|
||||
{
|
||||
struct fuse_notify_inval_inode_out outarg;
|
||||
struct fuse_ll *f;
|
||||
struct iovec iov[2];
|
||||
|
||||
if (!ch)
|
||||
return -EINVAL;
|
||||
|
||||
f = (struct fuse_ll *)fuse_session_data(fuse_chan_session(ch));
|
||||
if (!f)
|
||||
return -ENODEV;
|
||||
|
||||
outarg.ino = ino;
|
||||
outarg.off = off;
|
||||
outarg.len = len;
|
||||
|
||||
iov[1].iov_base = &outarg;
|
||||
iov[1].iov_len = sizeof(outarg);
|
||||
|
||||
return send_notify_iov(f, ch, FUSE_NOTIFY_INVAL_INODE, iov, 2);
|
||||
}
|
||||
|
||||
int fuse_lowlevel_notify_inval_entry(struct fuse_chan *ch, fuse_ino_t parent,
|
||||
const char *name, size_t namelen)
|
||||
{
|
||||
struct fuse_notify_inval_entry_out outarg;
|
||||
struct fuse_ll *f;
|
||||
struct iovec iov[3];
|
||||
|
||||
if (!ch)
|
||||
return -EINVAL;
|
||||
|
||||
f = (struct fuse_ll *)fuse_session_data(fuse_chan_session(ch));
|
||||
if (!f)
|
||||
return -ENODEV;
|
||||
|
||||
outarg.parent = parent;
|
||||
outarg.namelen = namelen;
|
||||
outarg.padding = 0;
|
||||
|
||||
iov[1].iov_base = &outarg;
|
||||
iov[1].iov_len = sizeof(outarg);
|
||||
iov[2].iov_base = (void *)name;
|
||||
iov[2].iov_len = namelen + 1;
|
||||
|
||||
return send_notify_iov(f, ch, FUSE_NOTIFY_INVAL_ENTRY, iov, 3);
|
||||
}
|
||||
|
||||
void *fuse_req_userdata(fuse_req_t req)
|
||||
{
|
||||
return req->f->userdata;
|
||||
@ -1280,6 +1349,19 @@ const struct fuse_ctx *fuse_req_ctx(fuse_req_t req)
|
||||
return &req->ctx;
|
||||
}
|
||||
|
||||
/*
|
||||
* The size of fuse_ctx got extended, so need to be careful about
|
||||
* incompatibility (i.e. a new binary cannot work with an old
|
||||
* library).
|
||||
*/
|
||||
const struct fuse_ctx *fuse_req_ctx_compat24(fuse_req_t req);
|
||||
const struct fuse_ctx *fuse_req_ctx_compat24(fuse_req_t req)
|
||||
{
|
||||
return fuse_req_ctx(req);
|
||||
}
|
||||
FUSE_SYMVER(".symver fuse_req_ctx_compat24,fuse_req_ctx@FUSE_2.4");
|
||||
|
||||
|
||||
void fuse_req_interrupt_func(fuse_req_t req, fuse_interrupt_func_t func,
|
||||
void *data)
|
||||
{
|
||||
|
@ -111,6 +111,11 @@ int fuse_session_exited(struct fuse_session *se)
|
||||
return se->exited;
|
||||
}
|
||||
|
||||
void *fuse_session_data(struct fuse_session *se)
|
||||
{
|
||||
return se->data;
|
||||
}
|
||||
|
||||
static struct fuse_chan *fuse_chan_new_common(struct fuse_chan_ops *op, int fd,
|
||||
size_t bufsize, void *data,
|
||||
int compat)
|
||||
|
@ -3,7 +3,6 @@ FUSE_2.2 {
|
||||
fuse_destroy;
|
||||
fuse_exit;
|
||||
fuse_exited;
|
||||
fuse_get_context;
|
||||
fuse_invalidate;
|
||||
fuse_is_lib_option;
|
||||
fuse_loop;
|
||||
@ -43,7 +42,6 @@ FUSE_2.4 {
|
||||
fuse_reply_readlink;
|
||||
fuse_reply_write;
|
||||
fuse_reply_xattr;
|
||||
fuse_req_ctx;
|
||||
fuse_req_userdata;
|
||||
fuse_session_add_chan;
|
||||
fuse_session_destroy;
|
||||
@ -176,6 +174,10 @@ FUSE_2.8 {
|
||||
fuse_reply_poll;
|
||||
fuse_req_getgroups;
|
||||
fuse_getgroups;
|
||||
fuse_req_ctx;
|
||||
fuse_get_context;
|
||||
fuse_lowlevel_notify_inval_inode;
|
||||
fuse_lowlevel_notify_inval_entry;
|
||||
|
||||
local:
|
||||
*;
|
||||
|
Loading…
Reference in New Issue
Block a user