mirror of
https://github.com/Motorhead1991/qemu.git
synced 2025-08-18 23:52:14 -06:00
fuse: (Partially) implement fallocate()
This allows allocating areas after the (old) EOF as part of a growing resize, writing zeroes, and discarding. Signed-off-by: Max Reitz <mreitz@redhat.com> Message-Id: <20201027190600.192171-6-mreitz@redhat.com> Signed-off-by: Kevin Wolf <kwolf@redhat.com>
This commit is contained in:
parent
4fba06d594
commit
4ca37a96a7
1 changed files with 84 additions and 0 deletions
|
@ -521,6 +521,89 @@ static void fuse_write(fuse_req_t req, fuse_ino_t inode, const char *buf,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Let clients perform various fallocate() operations.
|
||||||
|
*/
|
||||||
|
static void fuse_fallocate(fuse_req_t req, fuse_ino_t inode, int mode,
|
||||||
|
off_t offset, off_t length,
|
||||||
|
struct fuse_file_info *fi)
|
||||||
|
{
|
||||||
|
FuseExport *exp = fuse_req_userdata(req);
|
||||||
|
int64_t blk_len;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
if (!exp->writable) {
|
||||||
|
fuse_reply_err(req, EACCES);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
blk_len = blk_getlength(exp->common.blk);
|
||||||
|
if (blk_len < 0) {
|
||||||
|
fuse_reply_err(req, -blk_len);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mode & FALLOC_FL_KEEP_SIZE) {
|
||||||
|
length = MIN(length, blk_len - offset);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mode & FALLOC_FL_PUNCH_HOLE) {
|
||||||
|
if (!(mode & FALLOC_FL_KEEP_SIZE)) {
|
||||||
|
fuse_reply_err(req, EINVAL);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
do {
|
||||||
|
int size = MIN(length, BDRV_REQUEST_MAX_BYTES);
|
||||||
|
|
||||||
|
ret = blk_pdiscard(exp->common.blk, offset, size);
|
||||||
|
offset += size;
|
||||||
|
length -= size;
|
||||||
|
} while (ret == 0 && length > 0);
|
||||||
|
} else if (mode & FALLOC_FL_ZERO_RANGE) {
|
||||||
|
if (!(mode & FALLOC_FL_KEEP_SIZE) && offset + length > blk_len) {
|
||||||
|
/* No need for zeroes, we are going to write them ourselves */
|
||||||
|
ret = fuse_do_truncate(exp, offset + length, false,
|
||||||
|
PREALLOC_MODE_OFF);
|
||||||
|
if (ret < 0) {
|
||||||
|
fuse_reply_err(req, -ret);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
do {
|
||||||
|
int size = MIN(length, BDRV_REQUEST_MAX_BYTES);
|
||||||
|
|
||||||
|
ret = blk_pwrite_zeroes(exp->common.blk,
|
||||||
|
offset, size, 0);
|
||||||
|
offset += size;
|
||||||
|
length -= size;
|
||||||
|
} while (ret == 0 && length > 0);
|
||||||
|
} else if (!mode) {
|
||||||
|
/* We can only fallocate at the EOF with a truncate */
|
||||||
|
if (offset < blk_len) {
|
||||||
|
fuse_reply_err(req, EOPNOTSUPP);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (offset > blk_len) {
|
||||||
|
/* No preallocation needed here */
|
||||||
|
ret = fuse_do_truncate(exp, offset, true, PREALLOC_MODE_OFF);
|
||||||
|
if (ret < 0) {
|
||||||
|
fuse_reply_err(req, -ret);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = fuse_do_truncate(exp, offset + length, true,
|
||||||
|
PREALLOC_MODE_FALLOC);
|
||||||
|
} else {
|
||||||
|
ret = -EOPNOTSUPP;
|
||||||
|
}
|
||||||
|
|
||||||
|
fuse_reply_err(req, ret < 0 ? -ret : 0);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Let clients fsync the exported image.
|
* Let clients fsync the exported image.
|
||||||
*/
|
*/
|
||||||
|
@ -552,6 +635,7 @@ static const struct fuse_lowlevel_ops fuse_ops = {
|
||||||
.open = fuse_open,
|
.open = fuse_open,
|
||||||
.read = fuse_read,
|
.read = fuse_read,
|
||||||
.write = fuse_write,
|
.write = fuse_write,
|
||||||
|
.fallocate = fuse_fallocate,
|
||||||
.flush = fuse_flush,
|
.flush = fuse_flush,
|
||||||
.fsync = fuse_fsync,
|
.fsync = fuse_fsync,
|
||||||
};
|
};
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue