summaryrefslogtreecommitdiff
path: root/bitmap.c
diff options
context:
space:
mode:
authorNeil Brown <neilb@suse.de>2006-05-15 00:56:02 +0000
committerNeil Brown <neilb@suse.de>2006-05-15 00:56:02 +0000
commit4ccdb956000d19fd03c4192ce7b8b147e34a5af0 (patch)
treeae3e0aba17da4ff0b35ca17a588980b6a879c739 /bitmap.c
parentc4d831e164da10be75f915f9e06c529e90f55da9 (diff)
downloadmdadm-4ccdb956000d19fd03c4192ce7b8b147e34a5af0.tar.gz
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>
Diffstat (limited to 'bitmap.c')
-rw-r--r--bitmap.c59
1 files changed, 41 insertions, 18 deletions
diff --git a/bitmap.c b/bitmap.c
index b044cd8..33deab1 100644
--- a/bitmap.c
+++ b/bitmap.c
@@ -18,8 +18,6 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
-#include <sys/types.h>
-#include <sys/stat.h>
#include "mdadm.h"
#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)
{
+ /* 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;
bitmap_info_t *info;
- char buf[512];
- int n;
+ char *buf, *unaligned;
+ int n, skip;
+
+ unaligned = malloc(8192*2);
+ buf = (char*) ((unsigned long)unaligned | 8191)+1;
+ n = read(fd, buf, 8192);
info = malloc(sizeof(*info));
if (info == NULL) {
@@ -135,12 +140,15 @@ bitmap_info_t *bitmap_fd_read(int fd, int brief)
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 "
"file: %s\n", strerror(errno));
free(info);
+ free(unaligned);
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 */
@@ -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);
- while ((n = read(fd, buf, sizeof(buf))) > 0) {
+ while(read_bits < total_bits) {
unsigned long long remaining = total_bits - read_bits;
- if (remaining > sizeof(buf) * 8) /* we want the full buffer */
- remaining = sizeof(buf) * 8;
- if (remaining > n * 8) /* the file is truncated */
- remaining = n * 8;
- dirty_bits += count_dirty_bits(buf, remaining);
+ if (n == 0) {
+ n = read(fd, buf, 8192);
+ skip = 0;
+ if (n <= 0)
+ 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;
- if (read_bits >= total_bits) /* we've got what we want */
- break;
+ n = 0;
}
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 supertype *st = *stp;
- fd = open(filename, O_RDONLY);
- if (fd < 0) {
- fprintf(stderr, Name ": failed to open bitmap file %s: %s\n",
- filename, strerror(errno));
+ if (stat(filename, &stb) < 0) {
+ fprintf(stderr, Name ": failed to find file %s: %s\n",
+ filename, strerror(errno));
return NULL;
}
- fstat(fd, &stb);
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 */
if (!st) st = guess_super(fd);
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 */
*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);