block/nfs: cache allocated filesize for read-only files
If the file is readonly its not expected to grow so save the blocking call to nfs_fstat_async and use the value saved at connection time. Also important the monitor (and thus the main loop) will not hang if block device info is queried and the NFS share is unresponsive. Signed-off-by: Peter Lieven <pl@kamp.de> Reviewed-by: Jeff Cody <jcody@redhat.com> Reviewed-by: Max Reitz <mreitz@redhat.com> Message-id: 1440671441-7978-1-git-send-email-pl@kamp.de Signed-off-by: Jeff Cody <jcody@redhat.com>
This commit is contained in:
parent
055c6f912c
commit
18a8056e0b
36
block/nfs.c
36
block/nfs.c
@ -43,6 +43,7 @@ typedef struct NFSClient {
|
|||||||
int events;
|
int events;
|
||||||
bool has_zero_init;
|
bool has_zero_init;
|
||||||
AioContext *aio_context;
|
AioContext *aio_context;
|
||||||
|
blkcnt_t st_blocks;
|
||||||
} NFSClient;
|
} NFSClient;
|
||||||
|
|
||||||
typedef struct NFSRPC {
|
typedef struct NFSRPC {
|
||||||
@ -374,6 +375,7 @@ static int64_t nfs_client_open(NFSClient *client, const char *filename,
|
|||||||
}
|
}
|
||||||
|
|
||||||
ret = DIV_ROUND_UP(st.st_size, BDRV_SECTOR_SIZE);
|
ret = DIV_ROUND_UP(st.st_size, BDRV_SECTOR_SIZE);
|
||||||
|
client->st_blocks = st.st_blocks;
|
||||||
client->has_zero_init = S_ISREG(st.st_mode);
|
client->has_zero_init = S_ISREG(st.st_mode);
|
||||||
goto out;
|
goto out;
|
||||||
fail:
|
fail:
|
||||||
@ -464,6 +466,11 @@ static int64_t nfs_get_allocated_file_size(BlockDriverState *bs)
|
|||||||
NFSRPC task = {0};
|
NFSRPC task = {0};
|
||||||
struct stat st;
|
struct stat st;
|
||||||
|
|
||||||
|
if (bdrv_is_read_only(bs) &&
|
||||||
|
!(bs->open_flags & BDRV_O_NOCACHE)) {
|
||||||
|
return client->st_blocks * 512;
|
||||||
|
}
|
||||||
|
|
||||||
task.st = &st;
|
task.st = &st;
|
||||||
if (nfs_fstat_async(client->context, client->fh, nfs_co_generic_cb,
|
if (nfs_fstat_async(client->context, client->fh, nfs_co_generic_cb,
|
||||||
&task) != 0) {
|
&task) != 0) {
|
||||||
@ -484,6 +491,34 @@ static int nfs_file_truncate(BlockDriverState *bs, int64_t offset)
|
|||||||
return nfs_ftruncate(client->context, client->fh, offset);
|
return nfs_ftruncate(client->context, client->fh, offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Note that this will not re-establish a connection with the NFS server
|
||||||
|
* - it is effectively a NOP. */
|
||||||
|
static int nfs_reopen_prepare(BDRVReopenState *state,
|
||||||
|
BlockReopenQueue *queue, Error **errp)
|
||||||
|
{
|
||||||
|
NFSClient *client = state->bs->opaque;
|
||||||
|
struct stat st;
|
||||||
|
int ret = 0;
|
||||||
|
|
||||||
|
if (state->flags & BDRV_O_RDWR && bdrv_is_read_only(state->bs)) {
|
||||||
|
error_setg(errp, "Cannot open a read-only mount as read-write");
|
||||||
|
return -EACCES;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Update cache for read-only reopens */
|
||||||
|
if (!(state->flags & BDRV_O_RDWR)) {
|
||||||
|
ret = nfs_fstat(client->context, client->fh, &st);
|
||||||
|
if (ret < 0) {
|
||||||
|
error_setg(errp, "Failed to fstat file: %s",
|
||||||
|
nfs_get_error(client->context));
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
client->st_blocks = st.st_blocks;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static BlockDriver bdrv_nfs = {
|
static BlockDriver bdrv_nfs = {
|
||||||
.format_name = "nfs",
|
.format_name = "nfs",
|
||||||
.protocol_name = "nfs",
|
.protocol_name = "nfs",
|
||||||
@ -499,6 +534,7 @@ static BlockDriver bdrv_nfs = {
|
|||||||
.bdrv_file_open = nfs_file_open,
|
.bdrv_file_open = nfs_file_open,
|
||||||
.bdrv_close = nfs_file_close,
|
.bdrv_close = nfs_file_close,
|
||||||
.bdrv_create = nfs_file_create,
|
.bdrv_create = nfs_file_create,
|
||||||
|
.bdrv_reopen_prepare = nfs_reopen_prepare,
|
||||||
|
|
||||||
.bdrv_co_readv = nfs_co_readv,
|
.bdrv_co_readv = nfs_co_readv,
|
||||||
.bdrv_co_writev = nfs_co_writev,
|
.bdrv_co_writev = nfs_co_writev,
|
||||||
|
Loading…
Reference in New Issue
Block a user