mirror of
https://github.com/libfuse/libfuse.git
synced 2024-11-23 12:14:15 +08:00
libfuse: add store request
Request data to be stored in the kernel buffers for a given inode.
This commit is contained in:
parent
2fcbc2a5a9
commit
0741f702a5
@ -61,6 +61,9 @@
|
||||
|
||||
* The fuse_reply_fd() interface is converted to using buffers.
|
||||
|
||||
* libfuse: add store request. Request data to be stored in the
|
||||
kernel buffers for a given inode.
|
||||
|
||||
2010-06-23 Miklos Szeredi <miklos@szeredi.hu>
|
||||
|
||||
* Make the number of max background requests and congestion
|
||||
|
@ -63,6 +63,9 @@
|
||||
*
|
||||
* 7.14
|
||||
* - add splice support to fuse device
|
||||
*
|
||||
* 7.15
|
||||
* - add store notify
|
||||
*/
|
||||
|
||||
#ifndef _LINUX_FUSE_H
|
||||
@ -99,7 +102,7 @@
|
||||
#define FUSE_KERNEL_VERSION 7
|
||||
|
||||
/** Minor version number of this interface */
|
||||
#define FUSE_KERNEL_MINOR_VERSION 14
|
||||
#define FUSE_KERNEL_MINOR_VERSION 15
|
||||
|
||||
/** The node ID of the root inode */
|
||||
#define FUSE_ROOT_ID 1
|
||||
@ -291,6 +294,7 @@ enum fuse_notify_code {
|
||||
FUSE_NOTIFY_POLL = 1,
|
||||
FUSE_NOTIFY_INVAL_INODE = 2,
|
||||
FUSE_NOTIFY_INVAL_ENTRY = 3,
|
||||
FUSE_NOTIFY_STORE = 4,
|
||||
FUSE_NOTIFY_CODE_MAX,
|
||||
};
|
||||
|
||||
@ -599,4 +603,11 @@ struct fuse_notify_inval_entry_out {
|
||||
__u32 padding;
|
||||
};
|
||||
|
||||
struct fuse_notify_store_out {
|
||||
__u64 nodeid;
|
||||
__u64 offset;
|
||||
__u32 size;
|
||||
__u32 padding;
|
||||
};
|
||||
|
||||
#endif /* _LINUX_FUSE_H */
|
||||
|
@ -1224,6 +1224,31 @@ int fuse_lowlevel_notify_inval_inode(struct fuse_chan *ch, fuse_ino_t ino,
|
||||
int fuse_lowlevel_notify_inval_entry(struct fuse_chan *ch, fuse_ino_t parent,
|
||||
const char *name, size_t namelen);
|
||||
|
||||
/**
|
||||
* Store data to the kernel buffers
|
||||
*
|
||||
* Synchronously store data in the kernel buffers belonging to the
|
||||
* given inode. The stored data is marked up-to-date (no read will be
|
||||
* performed against it, unless it's invalidated or evicted from the
|
||||
* cache).
|
||||
*
|
||||
* If the stored data overflows the current file size, then the size
|
||||
* is extended, similarly to a write(2) on the filesystem.
|
||||
*
|
||||
* If this function returns an error, then the store wasn't fully
|
||||
* completed, but it may have been partially completed.
|
||||
*
|
||||
* @param ch the channel through which to send the invalidation
|
||||
* @param ino the inode number
|
||||
* @param offset the starting offset into the file to store to
|
||||
* @param bufv buffer vector
|
||||
* @param flags flags controlling the copy
|
||||
* @return zero for success, -errno for failure
|
||||
*/
|
||||
int fuse_lowlevel_notify_store(struct fuse_chan *ch, fuse_ino_t ino,
|
||||
off_t offset, struct fuse_bufvec *bufv,
|
||||
enum fuse_buf_copy_flags flags);
|
||||
|
||||
/* ----------------------------------------------------------- *
|
||||
* Utility functions *
|
||||
* ----------------------------------------------------------- */
|
||||
|
@ -133,6 +133,31 @@ void fuse_free_req(fuse_req_t req)
|
||||
destroy_req(req);
|
||||
}
|
||||
|
||||
static int fuse_send_msg(struct fuse_ll *f, struct fuse_chan *ch,
|
||||
struct iovec *iov, int count)
|
||||
{
|
||||
struct fuse_out_header *out = iov[0].iov_base;
|
||||
|
||||
out->len = iov_length(iov, count);
|
||||
if (f->debug) {
|
||||
if (out->unique == 0) {
|
||||
fprintf(stderr, "NOTIFY: code=%d length=%u\n",
|
||||
out->error, out->len);
|
||||
} else if (out->error) {
|
||||
fprintf(stderr,
|
||||
" unique: %llu, error: %i (%s), outsize: %i\n",
|
||||
(unsigned long long) out->unique, out->error,
|
||||
strerror(-out->error), out->len);
|
||||
} else {
|
||||
fprintf(stderr,
|
||||
" unique: %llu, success, outsize: %i\n",
|
||||
(unsigned long long) out->unique, out->len);
|
||||
}
|
||||
}
|
||||
|
||||
return fuse_chan_send(ch, iov, count);
|
||||
}
|
||||
|
||||
int fuse_send_reply_iov_nofree(fuse_req_t req, int error, struct iovec *iov,
|
||||
int count)
|
||||
{
|
||||
@ -145,24 +170,11 @@ int fuse_send_reply_iov_nofree(fuse_req_t req, int error, struct iovec *iov,
|
||||
|
||||
out.unique = req->unique;
|
||||
out.error = error;
|
||||
|
||||
iov[0].iov_base = &out;
|
||||
iov[0].iov_len = sizeof(struct fuse_out_header);
|
||||
out.len = iov_length(iov, count);
|
||||
|
||||
if (req->f->debug) {
|
||||
if (out.error) {
|
||||
fprintf(stderr,
|
||||
" unique: %llu, error: %i (%s), outsize: %i\n",
|
||||
(unsigned long long) out.unique, out.error,
|
||||
strerror(-out.error), out.len);
|
||||
} else {
|
||||
fprintf(stderr,
|
||||
" unique: %llu, success, outsize: %i\n",
|
||||
(unsigned long long) out.unique, out.len);
|
||||
}
|
||||
}
|
||||
|
||||
return fuse_chan_send(req->ch, iov, count);
|
||||
return fuse_send_msg(req->f, req->ch, iov, count);
|
||||
}
|
||||
|
||||
static int send_reply_iov(fuse_req_t req, int error, struct iovec *iov,
|
||||
@ -451,27 +463,6 @@ static void fuse_ll_clear_pipe(struct fuse_ll *f)
|
||||
}
|
||||
}
|
||||
|
||||
static int send_reply_iov_buf(fuse_req_t req, const struct iovec *iov,
|
||||
int count, const char *buf, size_t len)
|
||||
{
|
||||
int res;
|
||||
struct iovec *new_iov;
|
||||
|
||||
new_iov = malloc((count + 1) * sizeof(struct iovec));
|
||||
if (new_iov == NULL)
|
||||
return fuse_reply_err(req, ENOMEM);
|
||||
|
||||
memcpy(new_iov, iov, count * sizeof(struct iovec));
|
||||
new_iov[count].iov_base = (void *) buf;
|
||||
new_iov[count].iov_len = len;
|
||||
count++;
|
||||
|
||||
res = send_reply_iov(req, 0, new_iov, count);
|
||||
free(new_iov);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
static int read_back(int fd, char *buf, size_t len)
|
||||
{
|
||||
int res;
|
||||
@ -488,12 +479,13 @@ static int read_back(int fd, char *buf, size_t len)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int fuse_reply_data_iov(fuse_req_t req, struct iovec *iov, int iov_count,
|
||||
static int fuse_send_data_iov(struct fuse_ll *f, struct fuse_chan *ch,
|
||||
struct iovec *iov, int iov_count,
|
||||
struct fuse_bufvec *buf, unsigned int flags)
|
||||
{
|
||||
int res;
|
||||
size_t len = fuse_buf_size(buf);
|
||||
struct fuse_out_header out;
|
||||
struct fuse_out_header *out = iov[0].iov_base;
|
||||
struct fuse_ll_pipe *llp;
|
||||
int splice_flags;
|
||||
size_t pipesize;
|
||||
@ -508,7 +500,10 @@ static int fuse_reply_data_iov(fuse_req_t req, struct iovec *iov, int iov_count,
|
||||
.count = 1,
|
||||
};
|
||||
|
||||
if (req->f->broken_splice_nonblock)
|
||||
if (f->broken_splice_nonblock)
|
||||
goto fallback;
|
||||
|
||||
if (flags & FUSE_BUF_NO_SPLICE)
|
||||
goto fallback;
|
||||
|
||||
total_fd_size = 0;
|
||||
@ -522,28 +517,24 @@ static int fuse_reply_data_iov(fuse_req_t req, struct iovec *iov, int iov_count,
|
||||
if (total_fd_size < 2 * pagesize)
|
||||
goto fallback;
|
||||
|
||||
if (req->f->conn.proto_minor < 14 ||
|
||||
!(req->f->conn.want & FUSE_CAP_SPLICE_WRITE))
|
||||
if (f->conn.proto_minor < 14 ||
|
||||
!(f->conn.want & FUSE_CAP_SPLICE_WRITE))
|
||||
goto fallback;
|
||||
|
||||
llp = fuse_ll_get_pipe(req->f);
|
||||
llp = fuse_ll_get_pipe(f);
|
||||
if (llp == NULL)
|
||||
goto fallback;
|
||||
|
||||
iov[0].iov_base = &out;
|
||||
iov[0].iov_len = sizeof(struct fuse_out_header);
|
||||
|
||||
headerlen = iov_length(iov, iov_count);
|
||||
|
||||
out.unique = req->unique;
|
||||
out.error = 0;
|
||||
out.len = headerlen + len;
|
||||
out->len = headerlen + len;
|
||||
|
||||
/*
|
||||
* Heuristic for the required pipe size, does not work if the
|
||||
* source contains less than page size fragments
|
||||
*/
|
||||
pipesize = pagesize * (iov_count + buf->count + 1) + out.len;
|
||||
pipesize = pagesize * (iov_count + buf->count + 1) + out->len;
|
||||
|
||||
if (llp->size < pipesize) {
|
||||
if (llp->can_grow) {
|
||||
@ -560,15 +551,13 @@ static int fuse_reply_data_iov(fuse_req_t req, struct iovec *iov, int iov_count,
|
||||
|
||||
|
||||
res = vmsplice(llp->pipe[1], iov, iov_count, SPLICE_F_NONBLOCK);
|
||||
if (res == -1) {
|
||||
res = -errno;
|
||||
perror("fuse: vmsplice to pipe");
|
||||
return res;
|
||||
}
|
||||
if (res != sizeof(struct fuse_out_header)) {
|
||||
if (res == -1)
|
||||
goto fallback;
|
||||
|
||||
if (res != headerlen) {
|
||||
res = -EIO;
|
||||
fprintf(stderr, "fuse: short vmsplice to pipe: %u/%zu\n", res,
|
||||
sizeof(struct fuse_out_header));
|
||||
headerlen);
|
||||
goto clear_pipe;
|
||||
}
|
||||
|
||||
@ -590,13 +579,13 @@ static int fuse_reply_data_iov(fuse_req_t req, struct iovec *iov, int iov_count,
|
||||
* this combination of input and output.
|
||||
*/
|
||||
if (res == -EAGAIN)
|
||||
req->f->broken_splice_nonblock = 1;
|
||||
f->broken_splice_nonblock = 1;
|
||||
|
||||
pthread_setspecific(req->f->pipe_key, NULL);
|
||||
pthread_setspecific(f->pipe_key, NULL);
|
||||
fuse_ll_pipe_free(llp);
|
||||
goto fallback;
|
||||
}
|
||||
res = fuse_reply_err(req, errno);
|
||||
res = -res;
|
||||
goto clear_pipe;
|
||||
}
|
||||
|
||||
@ -619,10 +608,8 @@ static int fuse_reply_data_iov(fuse_req_t req, struct iovec *iov, int iov_count,
|
||||
*/
|
||||
|
||||
res = posix_memalign(&mbuf.mem, pagesize, len);
|
||||
if (res != 0) {
|
||||
res = fuse_reply_err(req, res);
|
||||
if (res != 0)
|
||||
goto clear_pipe;
|
||||
}
|
||||
|
||||
mem_buf.off = now_len;
|
||||
res = fuse_buf_copy(&mem_buf, buf, 0);
|
||||
@ -637,7 +624,7 @@ static int fuse_reply_data_iov(fuse_req_t req, struct iovec *iov, int iov_count,
|
||||
tmpbuf = malloc(headerlen);
|
||||
if (tmpbuf == NULL) {
|
||||
free(mbuf.mem);
|
||||
res = fuse_reply_err(req, ENOMEM);
|
||||
res = ENOMEM;
|
||||
goto clear_pipe;
|
||||
}
|
||||
res = read_back(llp->pipe[0], tmpbuf, headerlen);
|
||||
@ -652,8 +639,10 @@ static int fuse_reply_data_iov(fuse_req_t req, struct iovec *iov, int iov_count,
|
||||
goto clear_pipe;
|
||||
}
|
||||
len = now_len + extra_len;
|
||||
res = send_reply_iov_buf(req, iov, iov_count,
|
||||
mbuf.mem, len);
|
||||
iov[iov_count].iov_base = mbuf.mem;
|
||||
iov[iov_count].iov_len = len;
|
||||
iov_count++;
|
||||
res = fuse_send_msg(f, ch, iov, iov_count);
|
||||
free(mbuf.mem);
|
||||
return res;
|
||||
}
|
||||
@ -661,36 +650,36 @@ static int fuse_reply_data_iov(fuse_req_t req, struct iovec *iov, int iov_count,
|
||||
res = now_len;
|
||||
}
|
||||
len = res;
|
||||
out.len = len + sizeof(struct fuse_out_header);
|
||||
out->len = headerlen + len;
|
||||
|
||||
if (req->f->debug) {
|
||||
if (f->debug) {
|
||||
fprintf(stderr,
|
||||
" unique: %llu, success, outsize: %i (splice)\n",
|
||||
(unsigned long long) out.unique, out.len);
|
||||
(unsigned long long) out->unique, out->len);
|
||||
}
|
||||
|
||||
splice_flags = 0;
|
||||
if ((flags & FUSE_BUF_SPLICE_MOVE) &&
|
||||
(req->f->conn.want & FUSE_CAP_SPLICE_MOVE))
|
||||
(f->conn.want & FUSE_CAP_SPLICE_MOVE))
|
||||
splice_flags |= SPLICE_F_MOVE;
|
||||
|
||||
res = splice(llp->pipe[0], NULL,
|
||||
fuse_chan_fd(req->ch), NULL, out.len, splice_flags);
|
||||
fuse_chan_fd(ch), NULL, out->len, splice_flags);
|
||||
if (res == -1) {
|
||||
res = -errno;
|
||||
perror("fuse: splice from pipe");
|
||||
goto clear_pipe;
|
||||
}
|
||||
if (res != out.len) {
|
||||
if (res != out->len) {
|
||||
res = -EIO;
|
||||
fprintf(stderr, "fuse: short splice from pipe: %u/%u\n",
|
||||
res, out.len);
|
||||
res, out->len);
|
||||
goto clear_pipe;
|
||||
}
|
||||
return 0;
|
||||
|
||||
clear_pipe:
|
||||
fuse_ll_clear_pipe(req->f);
|
||||
fuse_ll_clear_pipe(f);
|
||||
return res;
|
||||
|
||||
fallback:
|
||||
@ -705,15 +694,19 @@ fallback:
|
||||
|
||||
res = posix_memalign(&mbuf.mem, pagesize, len);
|
||||
if (res != 0)
|
||||
return fuse_reply_err(req, res);
|
||||
return res;
|
||||
|
||||
res = fuse_buf_copy(&mem_buf, buf, 0);
|
||||
if (res < 0) {
|
||||
free(mbuf.mem);
|
||||
return fuse_reply_err(req, -res);
|
||||
return -res;
|
||||
}
|
||||
len = res;
|
||||
res = send_reply_iov_buf(req, iov, iov_count, mbuf.mem, len);
|
||||
|
||||
iov[iov_count].iov_base = mbuf.mem;
|
||||
iov[iov_count].iov_len = len;
|
||||
iov_count++;
|
||||
res = fuse_send_msg(f, ch, iov, iov_count);
|
||||
free(mbuf.mem);
|
||||
|
||||
return res;
|
||||
@ -723,8 +716,21 @@ fallback:
|
||||
int fuse_reply_data(fuse_req_t req, struct fuse_bufvec *bufv,
|
||||
enum fuse_buf_copy_flags flags)
|
||||
{
|
||||
struct iovec iov[1];
|
||||
return fuse_reply_data_iov(req, iov, 1, bufv, flags);
|
||||
struct iovec iov[2];
|
||||
struct fuse_out_header out;
|
||||
int res;
|
||||
|
||||
iov[0].iov_base = &out;
|
||||
iov[0].iov_len = sizeof(struct fuse_out_header);
|
||||
|
||||
out.unique = req->unique;
|
||||
out.error = 0;
|
||||
|
||||
res = fuse_send_data_iov(req->f, req->ch, iov, 1, bufv, flags);
|
||||
if (res <= 0)
|
||||
return res;
|
||||
else
|
||||
return fuse_reply_err(req, res);
|
||||
}
|
||||
|
||||
int fuse_reply_statfs(fuse_req_t req, const struct statvfs *stbuf)
|
||||
@ -1695,13 +1701,8 @@ static int send_notify_iov(struct fuse_ll *f, struct fuse_chan *ch,
|
||||
out.error = notify_code;
|
||||
iov[0].iov_base = &out;
|
||||
iov[0].iov_len = sizeof(struct fuse_out_header);
|
||||
out.len = iov_length(iov, count);
|
||||
|
||||
if (f->debug)
|
||||
fprintf(stderr, "NOTIFY: code=%d count=%d length=%u\n",
|
||||
notify_code, count, out.len);
|
||||
|
||||
return fuse_chan_send(ch, iov, count);
|
||||
return fuse_send_msg(f, ch, iov, count);
|
||||
}
|
||||
|
||||
int fuse_lowlevel_notify_poll(struct fuse_pollhandle *ph)
|
||||
@ -1771,6 +1772,43 @@ int fuse_lowlevel_notify_inval_entry(struct fuse_chan *ch, fuse_ino_t parent,
|
||||
return send_notify_iov(f, ch, FUSE_NOTIFY_INVAL_ENTRY, iov, 3);
|
||||
}
|
||||
|
||||
int fuse_lowlevel_notify_store(struct fuse_chan *ch, fuse_ino_t ino,
|
||||
off_t offset, struct fuse_bufvec *bufv,
|
||||
enum fuse_buf_copy_flags flags)
|
||||
{
|
||||
struct fuse_out_header out;
|
||||
struct fuse_notify_store_out outarg;
|
||||
struct fuse_ll *f;
|
||||
struct iovec iov[3];
|
||||
size_t size = fuse_buf_size(bufv);
|
||||
int res;
|
||||
|
||||
if (!ch)
|
||||
return -EINVAL;
|
||||
|
||||
f = (struct fuse_ll *)fuse_session_data(fuse_chan_session(ch));
|
||||
if (!f)
|
||||
return -ENODEV;
|
||||
|
||||
out.unique = 0;
|
||||
out.error = FUSE_NOTIFY_STORE;
|
||||
|
||||
outarg.nodeid = ino;
|
||||
outarg.offset = offset;
|
||||
outarg.size = size;
|
||||
|
||||
iov[0].iov_base = &out;
|
||||
iov[0].iov_len = sizeof(out);
|
||||
iov[1].iov_base = &outarg;
|
||||
iov[1].iov_len = sizeof(outarg);
|
||||
|
||||
res = fuse_send_data_iov(f, ch, iov, 2, bufv, flags);
|
||||
if (res > 0)
|
||||
res = -res;
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
void *fuse_req_userdata(fuse_req_t req)
|
||||
{
|
||||
return req->f->userdata;
|
||||
|
@ -184,6 +184,7 @@ FUSE_2.9 {
|
||||
global:
|
||||
fuse_buf_copy;
|
||||
fuse_buf_size;
|
||||
fuse_lowlevel_notify_store;
|
||||
fuse_reply_data;
|
||||
fuse_session_process_buf;
|
||||
fuse_session_receive_buf;
|
||||
|
Loading…
Reference in New Issue
Block a user