storage: reduce number of stat calls

We are calling fstat() at least twice per storage volume in
a directory storage pool; this is rather wasteful.  Refactoring
this is also a step towards making code reusable for gluster,
where gluster can provide struct stat but cannot use fstat().

* src/storage/storage_backend.h
(virStorageBackendVolOpenCheckMode)
(virStorageBackendUpdateVolTargetInfoFD): Update signature.
* src/storage/storage_backend.c
(virStorageBackendVolOpenCheckMode): Pass stat results back.
(virStorageBackendUpdateVolTargetInfoFD): Use existing stats.
(virStorageBackendVolOpen, virStorageBackendUpdateVolTargetInfo):
Update callers.
* src/storage/storage_backend_fs.c (virStorageBackendProbeTarget):
Likewise.
* src/storage/storage_backend_scsi.c
(virStorageBackendSCSIUpdateVolTargetInfo): Likewise.
* src/storage/storage_backend_mpath.c
(virStorageBackendMpathUpdateVolTargetInfo): Likewise.

Signed-off-by: Eric Blake <eblake@redhat.com>
This commit is contained in:
Eric Blake 2013-11-05 08:30:01 -07:00
parent 5327fad4f2
commit 9cac863965
5 changed files with 49 additions and 42 deletions

View File

@ -1152,30 +1152,30 @@ virStorageBackendForType(int type)
* volume is a dangling symbolic link. * volume is a dangling symbolic link.
*/ */
int int
virStorageBackendVolOpenCheckMode(const char *path, unsigned int flags) virStorageBackendVolOpenCheckMode(const char *path, struct stat *sb,
unsigned int flags)
{ {
int fd, mode = 0; int fd, mode = 0;
struct stat sb;
char *base = last_component(path); char *base = last_component(path);
if (lstat(path, &sb) < 0) { if (lstat(path, sb) < 0) {
virReportSystemError(errno, virReportSystemError(errno,
_("cannot stat file '%s'"), _("cannot stat file '%s'"),
path); path);
return -1; return -1;
} }
if (S_ISFIFO(sb.st_mode)) { if (S_ISFIFO(sb->st_mode)) {
VIR_WARN("ignoring FIFO '%s'", path); VIR_WARN("ignoring FIFO '%s'", path);
return -2; return -2;
} else if (S_ISSOCK(sb.st_mode)) { } else if (S_ISSOCK(sb->st_mode)) {
VIR_WARN("ignoring socket '%s'", path); VIR_WARN("ignoring socket '%s'", path);
return -2; return -2;
} }
if ((fd = open(path, O_RDONLY|O_NONBLOCK|O_NOCTTY)) < 0) { if ((fd = open(path, O_RDONLY|O_NONBLOCK|O_NOCTTY)) < 0) {
if ((errno == ENOENT || errno == ELOOP) && if ((errno == ENOENT || errno == ELOOP) &&
S_ISLNK(sb.st_mode)) { S_ISLNK(sb->st_mode)) {
VIR_WARN("ignoring dangling symlink '%s'", path); VIR_WARN("ignoring dangling symlink '%s'", path);
return -2; return -2;
} }
@ -1186,7 +1186,7 @@ virStorageBackendVolOpenCheckMode(const char *path, unsigned int flags)
return -1; return -1;
} }
if (fstat(fd, &sb) < 0) { if (fstat(fd, sb) < 0) {
virReportSystemError(errno, virReportSystemError(errno,
_("cannot stat file '%s'"), _("cannot stat file '%s'"),
path); path);
@ -1194,13 +1194,13 @@ virStorageBackendVolOpenCheckMode(const char *path, unsigned int flags)
return -1; return -1;
} }
if (S_ISREG(sb.st_mode)) if (S_ISREG(sb->st_mode))
mode = VIR_STORAGE_VOL_OPEN_REG; mode = VIR_STORAGE_VOL_OPEN_REG;
else if (S_ISCHR(sb.st_mode)) else if (S_ISCHR(sb->st_mode))
mode = VIR_STORAGE_VOL_OPEN_CHAR; mode = VIR_STORAGE_VOL_OPEN_CHAR;
else if (S_ISBLK(sb.st_mode)) else if (S_ISBLK(sb->st_mode))
mode = VIR_STORAGE_VOL_OPEN_BLOCK; mode = VIR_STORAGE_VOL_OPEN_BLOCK;
else if (S_ISDIR(sb.st_mode)) { else if (S_ISDIR(sb->st_mode)) {
mode = VIR_STORAGE_VOL_OPEN_DIR; mode = VIR_STORAGE_VOL_OPEN_DIR;
if (STREQ(base, ".") || if (STREQ(base, ".") ||
@ -1229,7 +1229,8 @@ virStorageBackendVolOpenCheckMode(const char *path, unsigned int flags)
int virStorageBackendVolOpen(const char *path) int virStorageBackendVolOpen(const char *path)
{ {
return virStorageBackendVolOpenCheckMode(path, struct stat sb;
return virStorageBackendVolOpenCheckMode(path, &sb,
VIR_STORAGE_VOL_OPEN_DEFAULT); VIR_STORAGE_VOL_OPEN_DEFAULT);
} }
@ -1240,14 +1241,16 @@ virStorageBackendUpdateVolTargetInfo(virStorageVolTargetPtr target,
unsigned int openflags) unsigned int openflags)
{ {
int ret, fd; int ret, fd;
struct stat sb;
if ((ret = virStorageBackendVolOpenCheckMode(target->path, if ((ret = virStorageBackendVolOpenCheckMode(target->path, &sb,
openflags)) < 0) openflags)) < 0)
return ret; return ret;
fd = ret; fd = ret;
ret = virStorageBackendUpdateVolTargetInfoFD(target, ret = virStorageBackendUpdateVolTargetInfoFD(target,
fd, fd,
&sb,
allocation, allocation,
capacity); capacity);
@ -1298,35 +1301,28 @@ int virStorageBackendUpdateVolInfo(virStorageVolDefPtr vol,
int int
virStorageBackendUpdateVolTargetInfoFD(virStorageVolTargetPtr target, virStorageBackendUpdateVolTargetInfoFD(virStorageVolTargetPtr target,
int fd, int fd,
struct stat *sb,
unsigned long long *allocation, unsigned long long *allocation,
unsigned long long *capacity) unsigned long long *capacity)
{ {
struct stat sb;
#if WITH_SELINUX #if WITH_SELINUX
security_context_t filecon = NULL; security_context_t filecon = NULL;
#endif #endif
if (fstat(fd, &sb) < 0) {
virReportSystemError(errno,
_("cannot stat file '%s'"),
target->path);
return -1;
}
if (allocation) { if (allocation) {
if (S_ISREG(sb.st_mode)) { if (S_ISREG(sb->st_mode)) {
#ifndef WIN32 #ifndef WIN32
*allocation = (unsigned long long)sb.st_blocks * *allocation = (unsigned long long)sb->st_blocks *
(unsigned long long)DEV_BSIZE; (unsigned long long)DEV_BSIZE;
#else #else
*allocation = sb.st_size; *allocation = sb->st_size;
#endif #endif
/* Regular files may be sparse, so logical size (capacity) is not same /* Regular files may be sparse, so logical size (capacity) is not same
* as actual allocation above * as actual allocation above
*/ */
if (capacity) if (capacity)
*capacity = sb.st_size; *capacity = sb->st_size;
} else if (S_ISDIR(sb.st_mode)) { } else if (S_ISDIR(sb->st_mode)) {
*allocation = 0; *allocation = 0;
if (capacity) if (capacity)
*capacity = 0; *capacity = 0;
@ -1351,16 +1347,16 @@ virStorageBackendUpdateVolTargetInfoFD(virStorageVolTargetPtr target,
} }
} }
target->perms.mode = sb.st_mode & S_IRWXUGO; target->perms.mode = sb->st_mode & S_IRWXUGO;
target->perms.uid = sb.st_uid; target->perms.uid = sb->st_uid;
target->perms.gid = sb.st_gid; target->perms.gid = sb->st_gid;
if (!target->timestamps && VIR_ALLOC(target->timestamps) < 0) if (!target->timestamps && VIR_ALLOC(target->timestamps) < 0)
return -1; return -1;
target->timestamps->atime = get_stat_atime(&sb); target->timestamps->atime = get_stat_atime(sb);
target->timestamps->btime = get_stat_birthtime(&sb); target->timestamps->btime = get_stat_birthtime(sb);
target->timestamps->ctime = get_stat_ctime(&sb); target->timestamps->ctime = get_stat_ctime(sb);
target->timestamps->mtime = get_stat_mtime(&sb); target->timestamps->mtime = get_stat_mtime(sb);
VIR_FREE(target->perms.label); VIR_FREE(target->perms.label);

View File

@ -24,6 +24,8 @@
#ifndef __VIR_STORAGE_BACKEND_H__ #ifndef __VIR_STORAGE_BACKEND_H__
# define __VIR_STORAGE_BACKEND_H__ # define __VIR_STORAGE_BACKEND_H__
# include <sys/stat.h>
# include "internal.h" # include "internal.h"
# include "storage_conf.h" # include "storage_conf.h"
# include "vircommand.h" # include "vircommand.h"
@ -108,9 +110,10 @@ enum {
VIR_STORAGE_VOL_OPEN_CHAR |\ VIR_STORAGE_VOL_OPEN_CHAR |\
VIR_STORAGE_VOL_OPEN_BLOCK) VIR_STORAGE_VOL_OPEN_BLOCK)
int virStorageBackendVolOpenCheckMode(const char *path, unsigned int flags) int virStorageBackendVolOpenCheckMode(const char *path, struct stat *sb,
ATTRIBUTE_RETURN_CHECK unsigned int flags)
ATTRIBUTE_NONNULL(1); ATTRIBUTE_RETURN_CHECK
ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2);
int virStorageBackendUpdateVolInfo(virStorageVolDefPtr vol, int virStorageBackendUpdateVolInfo(virStorageVolDefPtr vol,
int withCapacity); int withCapacity);
@ -124,6 +127,7 @@ int virStorageBackendUpdateVolTargetInfo(virStorageVolTargetPtr target,
unsigned int openflags); unsigned int openflags);
int virStorageBackendUpdateVolTargetInfoFD(virStorageVolTargetPtr target, int virStorageBackendUpdateVolTargetInfoFD(virStorageVolTargetPtr target,
int fd, int fd,
struct stat *sb,
unsigned long long *allocation, unsigned long long *allocation,
unsigned long long *capacity); unsigned long long *capacity);
int int

View File

@ -70,18 +70,19 @@ virStorageBackendProbeTarget(virStorageVolTargetPtr target,
int fd = -1; int fd = -1;
int ret = -1; int ret = -1;
virStorageFileMetadata *meta = NULL; virStorageFileMetadata *meta = NULL;
struct stat sb;
*backingStore = NULL; *backingStore = NULL;
*backingStoreFormat = VIR_STORAGE_FILE_AUTO; *backingStoreFormat = VIR_STORAGE_FILE_AUTO;
if (encryption) if (encryption)
*encryption = NULL; *encryption = NULL;
if ((ret = virStorageBackendVolOpenCheckMode(target->path, if ((ret = virStorageBackendVolOpenCheckMode(target->path, &sb,
VIR_STORAGE_VOL_FS_REFRESH_FLAGS)) < 0) VIR_STORAGE_VOL_FS_REFRESH_FLAGS)) < 0)
goto error; /* Take care to propagate ret, it is not always -1 */ goto error; /* Take care to propagate ret, it is not always -1 */
fd = ret; fd = ret;
if ((ret = virStorageBackendUpdateVolTargetInfoFD(target, fd, if ((ret = virStorageBackendUpdateVolTargetInfoFD(target, fd, &sb,
allocation, allocation,
capacity)) < 0) { capacity)) < 0) {
goto error; goto error;

View File

@ -1,7 +1,7 @@
/* /*
* storage_backend_mpath.c: storage backend for multipath handling * storage_backend_mpath.c: storage backend for multipath handling
* *
* Copyright (C) 2009-2011 Red Hat, Inc. * Copyright (C) 2009-2011, 2013 Red Hat, Inc.
* Copyright (C) 2009-2008 Dave Allan * Copyright (C) 2009-2008 Dave Allan
* *
* This library is free software; you can redistribute it and/or * This library is free software; you can redistribute it and/or
@ -46,13 +46,16 @@ virStorageBackendMpathUpdateVolTargetInfo(virStorageVolTargetPtr target,
{ {
int ret = -1; int ret = -1;
int fdret, fd = -1; int fdret, fd = -1;
struct stat sb;
if ((fdret = virStorageBackendVolOpen(target->path)) < 0) if ((fdret = virStorageBackendVolOpenCheckMode(target->path, &sb,
VIR_STORAGE_VOL_OPEN_DEFAULT)) < 0)
goto out; goto out;
fd = fdret; fd = fdret;
if (virStorageBackendUpdateVolTargetInfoFD(target, if (virStorageBackendUpdateVolTargetInfoFD(target,
fd, fd,
&sb,
allocation, allocation,
capacity) < 0) capacity) < 0)
goto out; goto out;

View File

@ -1,7 +1,7 @@
/* /*
* storage_backend_scsi.c: storage backend for SCSI handling * storage_backend_scsi.c: storage backend for SCSI handling
* *
* Copyright (C) 2007-2008 Red Hat, Inc. * Copyright (C) 2007-2008, 2013 Red Hat, Inc.
* Copyright (C) 2007-2008 Daniel P. Berrange * Copyright (C) 2007-2008 Daniel P. Berrange
* *
* This library is free software; you can redistribute it and/or * This library is free software; you can redistribute it and/or
@ -138,13 +138,16 @@ virStorageBackendSCSIUpdateVolTargetInfo(virStorageVolTargetPtr target,
{ {
int fdret, fd = -1; int fdret, fd = -1;
int ret = -1; int ret = -1;
struct stat sb;
if ((fdret = virStorageBackendVolOpen(target->path)) < 0) if ((fdret = virStorageBackendVolOpenCheckMode(target->path, &sb,
VIR_STORAGE_VOL_OPEN_DEFAULT)) < 0)
goto cleanup; goto cleanup;
fd = fdret; fd = fdret;
if (virStorageBackendUpdateVolTargetInfoFD(target, if (virStorageBackendUpdateVolTargetInfoFD(target,
fd, fd,
&sb,
allocation, allocation,
capacity) < 0) capacity) < 0)
goto cleanup; goto cleanup;