Use O_DIRECT to read bitmap files.
A pending patch to the kernel causes bitmap file updates to not go through the page cache, so O_DIRECT is needed to ensure that we read current data. Signed-off-by: Neil Brown <neilb@suse.de>
This commit is contained in:
parent
c4d831e164
commit
4ccdb95600
59
bitmap.c
59
bitmap.c
|
@ -18,8 +18,6 @@
|
||||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <sys/types.h>
|
|
||||||
#include <sys/stat.h>
|
|
||||||
#include "mdadm.h"
|
#include "mdadm.h"
|
||||||
|
|
||||||
#define min(a,b) (((a) < (b)) ? (a) : (b))
|
#define min(a,b) (((a) < (b)) ? (a) : (b))
|
||||||
|
@ -118,10 +116,17 @@ unsigned long long bitmap_bits(unsigned long long array_size,
|
||||||
|
|
||||||
bitmap_info_t *bitmap_fd_read(int fd, int brief)
|
bitmap_info_t *bitmap_fd_read(int fd, int brief)
|
||||||
{
|
{
|
||||||
|
/* Note: fd might be open O_DIRECT, so we must be
|
||||||
|
* careful to align reads properly
|
||||||
|
*/
|
||||||
unsigned long long total_bits = 0, read_bits = 0, dirty_bits = 0;
|
unsigned long long total_bits = 0, read_bits = 0, dirty_bits = 0;
|
||||||
bitmap_info_t *info;
|
bitmap_info_t *info;
|
||||||
char buf[512];
|
char *buf, *unaligned;
|
||||||
int n;
|
int n, skip;
|
||||||
|
|
||||||
|
unaligned = malloc(8192*2);
|
||||||
|
buf = (char*) ((unsigned long)unaligned | 8191)+1;
|
||||||
|
n = read(fd, buf, 8192);
|
||||||
|
|
||||||
info = malloc(sizeof(*info));
|
info = malloc(sizeof(*info));
|
||||||
if (info == NULL) {
|
if (info == NULL) {
|
||||||
|
@ -135,12 +140,15 @@ bitmap_info_t *bitmap_fd_read(int fd, int brief)
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (read(fd, &info->sb, sizeof(info->sb)) != sizeof(info->sb)) {
|
if (n < sizeof(info->sb)) {
|
||||||
fprintf(stderr, Name ": failed to read superblock of bitmap "
|
fprintf(stderr, Name ": failed to read superblock of bitmap "
|
||||||
"file: %s\n", strerror(errno));
|
"file: %s\n", strerror(errno));
|
||||||
free(info);
|
free(info);
|
||||||
|
free(unaligned);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
memcpy(&info->sb, buf, sizeof(info->sb));
|
||||||
|
skip = sizeof(info->sb);
|
||||||
|
|
||||||
sb_le_to_cpu(&info->sb); /* convert superblock to CPU byte ordering */
|
sb_le_to_cpu(&info->sb); /* convert superblock to CPU byte ordering */
|
||||||
|
|
||||||
|
@ -156,18 +164,22 @@ bitmap_info_t *bitmap_fd_read(int fd, int brief)
|
||||||
*/
|
*/
|
||||||
total_bits = bitmap_bits(info->sb.sync_size, info->sb.chunksize);
|
total_bits = bitmap_bits(info->sb.sync_size, info->sb.chunksize);
|
||||||
|
|
||||||
while ((n = read(fd, buf, sizeof(buf))) > 0) {
|
while(read_bits < total_bits) {
|
||||||
unsigned long long remaining = total_bits - read_bits;
|
unsigned long long remaining = total_bits - read_bits;
|
||||||
|
|
||||||
if (remaining > sizeof(buf) * 8) /* we want the full buffer */
|
if (n == 0) {
|
||||||
remaining = sizeof(buf) * 8;
|
n = read(fd, buf, 8192);
|
||||||
if (remaining > n * 8) /* the file is truncated */
|
skip = 0;
|
||||||
remaining = n * 8;
|
if (n <= 0)
|
||||||
dirty_bits += count_dirty_bits(buf, remaining);
|
break;
|
||||||
|
}
|
||||||
|
if (remaining > (n-skip) * 8) /* we want the full buffer */
|
||||||
|
remaining = (n-skip) * 8;
|
||||||
|
|
||||||
|
dirty_bits += count_dirty_bits(buf+skip, remaining);
|
||||||
|
|
||||||
read_bits += remaining;
|
read_bits += remaining;
|
||||||
if (read_bits >= total_bits) /* we've got what we want */
|
n = 0;
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (read_bits < total_bits) { /* file truncated... */
|
if (read_bits < total_bits) { /* file truncated... */
|
||||||
|
@ -189,14 +201,18 @@ bitmap_info_t *bitmap_file_read(char *filename, int brief, struct supertype **st
|
||||||
struct stat stb;
|
struct stat stb;
|
||||||
struct supertype *st = *stp;
|
struct supertype *st = *stp;
|
||||||
|
|
||||||
fd = open(filename, O_RDONLY);
|
if (stat(filename, &stb) < 0) {
|
||||||
if (fd < 0) {
|
fprintf(stderr, Name ": failed to find file %s: %s\n",
|
||||||
fprintf(stderr, Name ": failed to open bitmap file %s: %s\n",
|
filename, strerror(errno));
|
||||||
filename, strerror(errno));
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
fstat(fd, &stb);
|
|
||||||
if ((S_IFMT & stb.st_mode) == S_IFBLK) {
|
if ((S_IFMT & stb.st_mode) == S_IFBLK) {
|
||||||
|
fd = open(filename, O_RDONLY);
|
||||||
|
if (fd < 0) {
|
||||||
|
fprintf(stderr, Name ": failed to open bitmap file %s: %s\n",
|
||||||
|
filename, strerror(errno));
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
/* block device, so we are probably after an internal bitmap */
|
/* block device, so we are probably after an internal bitmap */
|
||||||
if (!st) st = guess_super(fd);
|
if (!st) st = guess_super(fd);
|
||||||
if (!st) {
|
if (!st) {
|
||||||
|
@ -207,6 +223,13 @@ bitmap_info_t *bitmap_file_read(char *filename, int brief, struct supertype **st
|
||||||
}
|
}
|
||||||
ioctl(fd, BLKFLSBUF, 0); /* make sure we read current data */
|
ioctl(fd, BLKFLSBUF, 0); /* make sure we read current data */
|
||||||
*stp = st;
|
*stp = st;
|
||||||
|
} else {
|
||||||
|
fd = open(filename, O_RDONLY|O_DIRECT);
|
||||||
|
if (fd < 0) {
|
||||||
|
fprintf(stderr, Name ": failed to open bitmap file %s: %s\n",
|
||||||
|
filename, strerror(errno));
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
info = bitmap_fd_read(fd, brief);
|
info = bitmap_fd_read(fd, brief);
|
||||||
|
|
2
config.c
2
config.c
|
@ -273,7 +273,7 @@ void arrayline(char *line)
|
||||||
mis.super_minor = UnSet;
|
mis.super_minor = UnSet;
|
||||||
mis.level = UnSet;
|
mis.level = UnSet;
|
||||||
mis.raid_disks = UnSet;
|
mis.raid_disks = UnSet;
|
||||||
mis.spare_disks = UnSet;
|
mis.spare_disks = 0;
|
||||||
mis.devices = NULL;
|
mis.devices = NULL;
|
||||||
mis.devname = NULL;
|
mis.devname = NULL;
|
||||||
mis.spare_group = NULL;
|
mis.spare_group = NULL;
|
||||||
|
|
3
mdadm.h
3
mdadm.h
|
@ -27,7 +27,7 @@
|
||||||
* Australia
|
* Australia
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#define __USE_LARGEFILE64
|
#define _GNU_SOURCE
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#ifndef __dietlibc__
|
#ifndef __dietlibc__
|
||||||
extern __off64_t lseek64 __P ((int __fd, __off64_t __offset, int __whence));
|
extern __off64_t lseek64 __P ((int __fd, __off64_t __offset, int __whence));
|
||||||
|
@ -292,7 +292,6 @@ struct stat64;
|
||||||
struct FTW {};
|
struct FTW {};
|
||||||
# define FTW_PHYS 1
|
# define FTW_PHYS 1
|
||||||
#else
|
#else
|
||||||
# define __USE_XOPEN_EXTENDED
|
|
||||||
# include <ftw.h>
|
# include <ftw.h>
|
||||||
# ifdef __dietlibc__
|
# ifdef __dietlibc__
|
||||||
# define FTW_PHYS 1
|
# define FTW_PHYS 1
|
||||||
|
|
Loading…
Reference in New Issue