#include <sys/un.h>
#include <sys/resource.h>
#include <sys/vfs.h>
+#include <sys/mman.h>
#include <linux/magic.h>
#include <poll.h>
#include <ctype.h>
static char *cluster_name = NULL;
/* Create the lockspace, take bitmapXXX locks on all the bitmaps. */
-int cluster_get_dlmlock(int *lockid)
+int cluster_get_dlmlock(void)
{
int ret = -1;
char str[64];
int flags = LKF_NOQUEUE;
+ int retry_count = 0;
+
+ if (!dlm_funs_ready()) {
+ pr_err("Something wrong with dlm library\n");
+ return -1;
+ }
ret = get_cluster_name(&cluster_name);
if (ret) {
}
dlm_lock_res = xmalloc(sizeof(struct dlm_lock_resource));
- dlm_lock_res->ls = dlm_hooks->create_lockspace(cluster_name, O_RDWR);
+ dlm_lock_res->ls = dlm_hooks->open_lockspace(cluster_name);
if (!dlm_lock_res->ls) {
- pr_err("%s failed to create lockspace\n", cluster_name);
- return -ENOMEM;
+ dlm_lock_res->ls = dlm_hooks->create_lockspace(cluster_name, O_RDWR);
+ if (!dlm_lock_res->ls) {
+ pr_err("%s failed to create lockspace\n", cluster_name);
+ return -ENOMEM;
+ }
+ } else {
+ pr_err("open existed %s lockspace\n", cluster_name);
}
snprintf(str, 64, "bitmap%s", cluster_name);
- ret = dlm_hooks->ls_lock(dlm_lock_res->ls, LKM_PWMODE, &dlm_lock_res->lksb,
- flags, str, strlen(str), 0, dlm_ast,
- dlm_lock_res, NULL, NULL);
+retry:
+ ret = dlm_hooks->ls_lock(dlm_lock_res->ls, LKM_PWMODE,
+ &dlm_lock_res->lksb, flags, str, strlen(str),
+ 0, dlm_ast, dlm_lock_res, NULL, NULL);
if (ret) {
pr_err("error %d when get PW mode on lock %s\n", errno, str);
+ /* let's try several times if EAGAIN happened */
+ if (dlm_lock_res->lksb.sb_status == EAGAIN && retry_count < 10) {
+ sleep(10);
+ retry_count++;
+ goto retry;
+ }
dlm_hooks->release_lockspace(cluster_name, dlm_lock_res->ls, 1);
return ret;
}
/* Wait for it to complete */
poll_for_ast(dlm_lock_res->ls);
- *lockid = dlm_lock_res->lksb.sb_lkid;
- return dlm_lock_res->lksb.sb_status;
+ if (dlm_lock_res->lksb.sb_status) {
+ pr_err("failed to lock cluster\n");
+ return -1;
+ }
+ return 1;
}
-int cluster_release_dlmlock(int lockid)
+int cluster_release_dlmlock(void)
{
int ret = -1;
if (!cluster_name)
- return -1;
+ goto out;
+
+ if (!dlm_lock_res->lksb.sb_lkid)
+ goto out;
- ret = dlm_hooks->ls_unlock(dlm_lock_res->ls, lockid, 0,
- &dlm_lock_res->lksb, dlm_lock_res);
+ ret = dlm_hooks->ls_unlock_wait(dlm_lock_res->ls,
+ dlm_lock_res->lksb.sb_lkid, 0,
+ &dlm_lock_res->lksb);
if (ret) {
pr_err("error %d happened when unlock\n", errno);
/* XXX make sure the lock is unlocked eventually */
errno = dlm_lock_res->lksb.sb_status;
if (errno != EUNLOCK) {
- pr_err("error %d happened in ast when unlock lockspace\n", errno);
+ pr_err("error %d happened in ast when unlock lockspace\n",
+ errno);
/* XXX make sure the lockspace is unlocked eventually */
goto out;
}
{
struct mdinfo *sra;
struct mdu_array_info_s array;
- int ret;
+ int ret = 0;
sra = sysfs_read(fd, NULL, GET_ARRAY_STATE);
if (sra) {
- if (sra->array_state != ARRAY_CLEAR &&
- sra->array_state != ARRAY_INACTIVE &&
- sra->array_state != ARRAY_UNKNOWN_STATE)
- ret = 0;
- else
+ if (!md_array_is_active(sra))
ret = -ENODEV;
free(sra);
return !ret;
}
+int md_array_is_active(struct mdinfo *info)
+{
+ return (info->array_state != ARRAY_CLEAR &&
+ info->array_state != ARRAY_INACTIVE &&
+ info->array_state != ARRAY_UNKNOWN_STATE);
+}
+
/*
* Get array info from the kernel. Longer term we want to deprecate the
* ioctl and get it from sysfs.
return ioctl(fd, GET_DISK_INFO, disk);
}
-/*
- * Parse a 128 bit uuid in 4 integers
- * format is 32 hexx nibbles with options :.<space> separator
- * If not exactly 32 hex digits are found, return 0
- * else return 1
- */
-int parse_uuid(char *str, int uuid[4])
-{
- int hit = 0; /* number of Hex digIT */
- int i;
- char c;
- for (i = 0; i < 4; i++)
- uuid[i] = 0;
-
- while ((c = *str++) != 0) {
- int n;
- if (c >= '0' && c <= '9')
- n = c-'0';
- else if (c >= 'a' && c <= 'f')
- n = 10 + c - 'a';
- else if (c >= 'A' && c <= 'F')
- n = 10 + c - 'A';
- else if (strchr(":. -", c))
- continue;
- else return 0;
-
- if (hit<32) {
- uuid[hit/8] <<= 4;
- uuid[hit/8] += n;
- }
- hit++;
- }
- if (hit == 32)
- return 1;
- return 0;
-}
-
int get_linux_version()
{
struct utsname name;
unsigned long long parse_size(char *size)
{
/* parse 'size' which should be a number optionally
- * followed by 'K', 'M', or 'G'.
+ * followed by 'K', 'M'. 'G' or 'T'.
* Without a suffix, K is assumed.
* Number returned is in sectors (half-K)
* INVALID_SECTORS returned on error.
c++;
s *= 1024 * 1024 * 2;
break;
+ case 'T':
+ c++;
+ s *= 1024 * 1024 * 1024 * 2LL;
+ break;
case 's': /* sectors */
c++;
break;
return s;
}
+int is_near_layout_10(int layout)
+{
+ int fc, fo;
+
+ fc = (layout >> 8) & 255;
+ fo = layout & (1 << 16);
+ if (fc > 1 || fo > 0)
+ return 0;
+ return 1;
+}
+
int parse_layout_10(char *layout)
{
int copies, rv;
}
}
-const int uuid_zero[4] = { 0, 0, 0, 0 };
-
-int same_uuid(int a[4], int b[4], int swapuuid)
-{
- if (swapuuid) {
- /* parse uuids are hostendian.
- * uuid's from some superblocks are big-ending
- * if there is a difference, we need to swap..
- */
- unsigned char *ac = (unsigned char *)a;
- unsigned char *bc = (unsigned char *)b;
- int i;
- for (i = 0; i < 16; i += 4) {
- if (ac[i+0] != bc[i+3] ||
- ac[i+1] != bc[i+2] ||
- ac[i+2] != bc[i+1] ||
- ac[i+3] != bc[i+0])
- return 0;
- }
- return 1;
- } else {
- if (a[0]==b[0] &&
- a[1]==b[1] &&
- a[2]==b[2] &&
- a[3]==b[3])
- return 1;
- return 0;
- }
-}
-
-void copy_uuid(void *a, int b[4], int swapuuid)
-{
- if (swapuuid) {
- /* parse uuids are hostendian.
- * uuid's from some superblocks are big-ending
- * if there is a difference, we need to swap..
- */
- unsigned char *ac = (unsigned char *)a;
- unsigned char *bc = (unsigned char *)b;
- int i;
- for (i = 0; i < 16; i += 4) {
- ac[i+0] = bc[i+3];
- ac[i+1] = bc[i+2];
- ac[i+2] = bc[i+1];
- ac[i+3] = bc[i+0];
- }
- } else
- memcpy(a, b, 16);
-}
-
char *__fname_from_uuid(int id[4], int swap, char *buf, char sep)
{
int i, j;
}
-char *fname_from_uuid(struct supertype *st, struct mdinfo *info, char *buf, char sep)
+char *fname_from_uuid(struct supertype *st, struct mdinfo *info,
+ char *buf, char sep)
{
// dirty hack to work around an issue with super1 superblocks...
// super1 superblocks need swapuuid set in order for assembly to
// work, but can't have it set if we want this printout to match
// all the other uuid printouts in super1.c, so we force swapuuid
// to 1 to make our printout match the rest of super1
- return __fname_from_uuid(info->uuid, (st->ss == &super1) ? 1 : st->ss->swapuuid, buf, sep);
+#if __BYTE_ORDER == BIG_ENDIAN
+ return __fname_from_uuid(info->uuid, 1, buf, sep);
+#else
+ return __fname_from_uuid(info->uuid, (st->ss == &super1) ? 1 :
+ st->ss->swapuuid, buf, sep);
+#endif
}
int check_ext2(int fd, char *name)
{
static char buf[47];
- /* We convert bytes to either centi-M{ega,ibi}bytes or
- * centi-G{igi,ibi}bytes, with appropriate rounding,
- * and then print 1/100th of those as a decimal.
+ /* We convert bytes to either centi-M{ega,ibi}bytes,
+ * centi-G{igi,ibi}bytes or centi-T{era,ebi}bytes
+ * with appropriate rounding, and then print
+ * 1/100th of those as a decimal.
* We allow upto 2048Megabytes before converting to
- * gigabytes, as that shows more precision and isn't
+ * gigabytes and 2048Gigabytes before converting to
+ * terabytes, as that shows more precision and isn't
* too large a number.
- * Terabytes are not yet handled.
*/
if (bytes < 5000*1024)
long cMB = (bytes / ( 1000000LL / 200LL ) +1) /2;
snprintf(buf, sizeof(buf), " (%ld.%02ld MiB %ld.%02ld MB)",
cMiB/100, cMiB % 100, cMB/100, cMB % 100);
- } else {
+ } else if (bytes < 2*1024LL*1024LL*1024LL*1024LL) {
long cGiB = (bytes * 200LL / (1LL<<30) +1) / 2;
long cGB = (bytes / (1000000000LL/200LL ) +1) /2;
snprintf(buf, sizeof(buf), " (%ld.%02ld GiB %ld.%02ld GB)",
cGiB/100, cGiB % 100, cGB/100, cGB % 100);
+ } else {
+ long cTiB = (bytes * 200LL / (1LL<<40) + 1) / 2;
+ long cTB = (bytes / (1000000000000LL / 200LL) + 1) / 2;
+ snprintf(buf, sizeof(buf), " (%ld.%02ld TiB %ld.%02ld TB)",
+ cTiB/100, cTiB % 100, cTB/100, cTB % 100);
}
return buf;
}
{
static char buf[30];
- /* We convert bytes to either centi-M{ega,ibi}bytes or
- * centi-G{igi,ibi}bytes, with appropriate rounding,
- * and then print 1/100th of those as a decimal.
+ /* We convert bytes to either centi-M{ega,ibi}bytes,
+ * centi-G{igi,ibi}bytes or centi-T{era,ebi}bytes
+ * with appropriate rounding, and then print
+ * 1/100th of those as a decimal.
* We allow upto 2048Megabytes before converting to
- * gigabytes, as that shows more precision and isn't
+ * gigabytes and 2048Gigabytes before converting to
+ * terabytes, as that shows more precision and isn't
* too large a number.
- * Terabytes are not yet handled.
*
* If prefix == IEC, we mean prefixes like kibi,mebi,gibi etc.
* If prefix == JEDEC, we mean prefixes like kilo,mega,giga etc.
long cMiB = (bytes * 200LL / (1LL<<20) +1) /2;
snprintf(buf, sizeof(buf), "%ld.%02ldMiB",
cMiB/100, cMiB % 100);
- } else {
+ } else if (bytes < 2*1024LL*1024LL*1024LL*1024LL) {
long cGiB = (bytes * 200LL / (1LL<<30) +1) /2;
snprintf(buf, sizeof(buf), "%ld.%02ldGiB",
cGiB/100, cGiB % 100);
+ } else {
+ long cTiB = (bytes * 200LL / (1LL<<40) + 1) / 2;
+ snprintf(buf, sizeof(buf), "%ld.%02ldTiB",
+ cTiB/100, cTiB % 100);
}
}
else if (prefix == JEDEC) {
long cMB = (bytes / ( 1000000LL / 200LL ) +1) /2;
snprintf(buf, sizeof(buf), "%ld.%02ldMB",
cMB/100, cMB % 100);
- } else {
+ } else if (bytes < 2*1024LL*1024LL*1024LL*1024LL) {
long cGB = (bytes / (1000000000LL/200LL ) +1) /2;
snprintf(buf, sizeof(buf), "%ld.%02ldGB",
cGB/100, cGB % 100);
+ } else {
+ long cTB = (bytes / (1000000000000LL / 200LL) + 1) / 2;
+ snprintf(buf, sizeof(buf), "%ld.%02ldTB",
+ cTB/100, cTB % 100);
}
}
else
if (strncmp(devnm, "md_", 3) == 0) {
snprintf(devname, sizeof(devname), "/dev/md/%s",
devnm + 3);
- if (stat(devname, &stb) == 0
- && (S_IFMT&stb.st_mode) == S_IFBLK
- && (stb.st_rdev == rdev))
+ if (stat(devname, &stb) == 0 &&
+ (S_IFMT&stb.st_mode) == S_IFBLK && (stb.st_rdev == rdev))
return devname;
}
snprintf(devname, sizeof(devname), "/dev/%s", devnm);
- if (stat(devname, &stb) == 0
- && (S_IFMT&stb.st_mode) == S_IFBLK
- && (stb.st_rdev == rdev))
+ if (stat(devname, &stb) == 0 && (S_IFMT&stb.st_mode) == S_IFBLK &&
+ (stb.st_rdev == rdev))
return devname;
snprintf(devname, sizeof(devname), "/dev/md/%s", devnm+2);
- if (stat(devname, &stb) == 0
- && (S_IFMT&stb.st_mode) == S_IFBLK
- && (stb.st_rdev == rdev))
+ if (stat(devname, &stb) == 0 && (S_IFMT&stb.st_mode) == S_IFBLK &&
+ (stb.st_rdev == rdev))
return devname;
dn = map_dev(major(rdev), minor(rdev), 0);
if (errno != EEXIST)
return NULL;
- if (stat(devname, &stb) == 0
- && (S_IFMT&stb.st_mode) == S_IFBLK
- && (stb.st_rdev == rdev))
+ if (stat(devname, &stb) == 0 && (S_IFMT&stb.st_mode) == S_IFBLK &&
+ (stb.st_rdev == rdev))
return devname;
unlink(devname);
return NULL;
}
if (fd < 0) {
/* Try /tmp as /dev appear to be read-only */
- snprintf(devname, sizeof(devname), "/tmp/.tmp.md.%d:%d:%d",
+ snprintf(devname, sizeof(devname),
+ "/tmp/.tmp.md.%d:%d:%d",
(int)getpid(), major, minor);
- if (mknod(devname, S_IFBLK|0600, makedev(major, minor)) == 0) {
+ if (mknod(devname, S_IFBLK|0600,
+ makedev(major, minor)) == 0) {
fd = open(devname, flags);
unlink(devname);
}
delay *= 2;
}
if (i == 25)
- dprintf("timeout waiting for %s\n", dev);
+ pr_err("timeout waiting for %s\n", dev);
}
struct superswitch *superlist[] =
return 0;
}
+int dev_sector_size_from_id(dev_t id, unsigned int *size)
+{
+ char buf[20];
+ int fd;
+
+ sprintf(buf, "%d:%d", major(id), minor(id));
+ fd = dev_open(buf, O_RDONLY);
+ if (fd < 0)
+ return 0;
+ if (get_dev_sector_size(fd, NULL, size)) {
+ close(fd);
+ return 1;
+ }
+ close(fd);
+ return 0;
+}
+
struct supertype *dup_super(struct supertype *orig)
{
struct supertype *st;
int start_mdmon(char *devnm)
{
- int i, skipped;
+ int i;
int len;
pid_t pid;
int status;
if (check_env("MDADM_NO_MDMON"))
return 0;
+ if (continue_via_systemd(devnm, MDMON_SERVICE))
+ return 0;
+ /* That failed, try running mdmon directly */
len = readlink("/proc/self/exe", pathbuf, sizeof(pathbuf)-1);
if (len > 0) {
char *sl;
} else
pathbuf[0] = '\0';
- /* First try to run systemctl */
- if (!check_env("MDADM_NO_SYSTEMCTL"))
- switch(fork()) {
- case 0:
- /* FIXME yuk. CLOSE_EXEC?? */
- skipped = 0;
- for (i = 3; skipped < 20; i++)
- if (close(i) < 0)
- skipped++;
- else
- skipped = 0;
-
- /* Don't want to see error messages from
- * systemctl. If the service doesn't exist,
- * we start mdmon ourselves.
- */
- close(2);
- open("/dev/null", O_WRONLY);
- snprintf(pathbuf, sizeof(pathbuf), "mdmon@%s.service",
- devnm);
- status = execl("/usr/bin/systemctl", "systemctl",
- "start",
- pathbuf, NULL);
- status = execl("/bin/systemctl", "systemctl", "start",
- pathbuf, NULL);
- exit(1);
- case -1: pr_err("cannot run mdmon. Array remains readonly\n");
- return -1;
- default: /* parent - good */
- pid = wait(&status);
- if (pid >= 0 && status == 0)
- return 0;
- }
-
- /* That failed, try running mdmon directly */
switch(fork()) {
case 0:
- /* FIXME yuk. CLOSE_EXEC?? */
- skipped = 0;
- for (i = 3; skipped < 20; i++)
- if (close(i) < 0)
- skipped++;
- else
- skipped = 0;
-
+ manage_fork_fds(1);
for (i = 0; paths[i]; i++)
if (paths[i][0]) {
execl(paths[i], paths[i],
unsigned int __invalid_size_argument_for_IOC = 0;
#endif
-int experimental(void)
-{
- if (check_env("MDADM_EXPERIMENTAL"))
- return 1;
- else {
- pr_err("To use this feature MDADM_EXPERIMENTAL environment variable has to be defined.\n");
- return 0;
- }
-}
-
/* Pick all spares matching given criteria from a container
* if min_size == 0 do not check size
* if domlist == NULL do not check domains
if (d->disk.state == 0) {
/* check if size is acceptable */
unsigned long long dev_size;
+ unsigned int dev_sector_size;
+ int size_valid = 0;
+ int sector_size_valid = 0;
+
dev_t dev = makedev(d->disk.major,d->disk.minor);
if (!criteria->min_size ||
(dev_size_from_id(dev, &dev_size) &&
dev_size >= criteria->min_size))
- found = 1;
+ size_valid = 1;
+
+ if (!criteria->sector_size ||
+ (dev_sector_size_from_id(dev, &dev_sector_size) &&
+ criteria->sector_size == dev_sector_size))
+ sector_size_valid = 1;
+
+ found = size_valid && sector_size_valid;
+
/* check if domain matches */
if (found && domlist) {
struct dev_policy *pol = devid_policy(dev);
{
unsigned int fds = 20 + devices;
struct rlimit lim;
- if (getrlimit(RLIMIT_NOFILE, &lim) != 0
- || lim.rlim_cur >= fds)
+ if (getrlimit(RLIMIT_NOFILE, &lim) != 0 || lim.rlim_cur >= fds)
return;
if (lim.rlim_max < fds)
lim.rlim_max = fds;
setrlimit(RLIMIT_NOFILE, &lim);
}
+/* Close all opened descriptors if needed and redirect
+ * streams to /dev/null.
+ * For debug purposed, leave STDOUT and STDERR untouched
+ * Returns:
+ * 1- if any error occurred
+ * 0- otherwise
+ */
+void manage_fork_fds(int close_all)
+{
+ DIR *dir;
+ struct dirent *dirent;
+
+ close(0);
+ open("/dev/null", O_RDWR);
+
+#ifndef DEBUG
+ dup2(0, 1);
+ dup2(0, 2);
+#endif
+
+ if (close_all == 0)
+ return;
+
+ dir = opendir("/proc/self/fd");
+ if (!dir) {
+ pr_err("Cannot open /proc/self/fd directory.\n");
+ return;
+ }
+ for (dirent = readdir(dir); dirent; dirent = readdir(dir)) {
+ int fd = -1;
+
+ if ((strcmp(dirent->d_name, ".") == 0) ||
+ (strcmp(dirent->d_name, "..")) == 0)
+ continue;
+
+ fd = strtol(dirent->d_name, NULL, 10);
+ if (fd > 2)
+ close(fd);
+ }
+}
+
+/* In a systemd/udev world, it is best to get systemd to
+ * run daemon rather than running in the background.
+ * Returns:
+ * 1- if systemd service has been started
+ * 0- otherwise
+ */
+int continue_via_systemd(char *devnm, char *service_name)
+{
+ int pid, status;
+ char pathbuf[1024];
+
+ /* Simply return that service cannot be started */
+ if (check_env("MDADM_NO_SYSTEMCTL"))
+ return 0;
+ switch (fork()) {
+ case 0:
+ manage_fork_fds(1);
+ snprintf(pathbuf, sizeof(pathbuf),
+ "%s@%s.service", service_name, devnm);
+ status = execl("/usr/bin/systemctl", "systemctl", "restart",
+ pathbuf, NULL);
+ status = execl("/bin/systemctl", "systemctl", "restart",
+ pathbuf, NULL);
+ exit(1);
+ case -1: /* Just do it ourselves. */
+ break;
+ default: /* parent - good */
+ pid = wait(&status);
+ if (pid >= 0 && status == 0)
+ return 1;
+ }
+ return 0;
+}
+
int in_initrd(void)
{
/* This is based on similar function in systemd. */
if (!cmap_hooks->cmap_handle)
return;
- cmap_hooks->initialize = dlsym(cmap_hooks->cmap_handle, "cmap_initialize");
- cmap_hooks->get_string = dlsym(cmap_hooks->cmap_handle, "cmap_get_string");
+ cmap_hooks->initialize =
+ dlsym(cmap_hooks->cmap_handle, "cmap_initialize");
+ cmap_hooks->get_string =
+ dlsym(cmap_hooks->cmap_handle, "cmap_get_string");
cmap_hooks->finalize = dlsym(cmap_hooks->cmap_handle, "cmap_finalize");
if (!cmap_hooks->initialize || !cmap_hooks->get_string ||
if (!dlm_hooks->dlm_handle)
return;
- dlm_hooks->create_lockspace = dlsym(dlm_hooks->dlm_handle, "dlm_create_lockspace");
- dlm_hooks->release_lockspace = dlsym(dlm_hooks->dlm_handle, "dlm_release_lockspace");
+ dlm_hooks->open_lockspace =
+ dlsym(dlm_hooks->dlm_handle, "dlm_open_lockspace");
+ dlm_hooks->create_lockspace =
+ dlsym(dlm_hooks->dlm_handle, "dlm_create_lockspace");
+ dlm_hooks->release_lockspace =
+ dlsym(dlm_hooks->dlm_handle, "dlm_release_lockspace");
dlm_hooks->ls_lock = dlsym(dlm_hooks->dlm_handle, "dlm_ls_lock");
- dlm_hooks->ls_unlock = dlsym(dlm_hooks->dlm_handle, "dlm_ls_unlock");
+ dlm_hooks->ls_unlock_wait =
+ dlsym(dlm_hooks->dlm_handle, "dlm_ls_unlock_wait");
dlm_hooks->ls_get_fd = dlsym(dlm_hooks->dlm_handle, "dlm_ls_get_fd");
dlm_hooks->dispatch = dlsym(dlm_hooks->dlm_handle, "dlm_dispatch");
- if (!dlm_hooks->create_lockspace || !dlm_hooks->ls_lock ||
- !dlm_hooks->ls_unlock || !dlm_hooks->release_lockspace ||
- !dlm_hooks->ls_get_fd || !dlm_hooks->dispatch)
+ if (!dlm_hooks->open_lockspace || !dlm_hooks->create_lockspace ||
+ !dlm_hooks->ls_lock || !dlm_hooks->ls_unlock_wait ||
+ !dlm_hooks->release_lockspace || !dlm_hooks->ls_get_fd ||
+ !dlm_hooks->dispatch)
dlclose(dlm_hooks->dlm_handle);
else
is_dlm_hooks_ready = 1;
set_dlm_hooks();
set_cmap_hooks();
}
+
+int zero_disk_range(int fd, unsigned long long sector, size_t count)
+{
+ int ret = 0;
+ int fd_zero;
+ void *addr = NULL;
+ size_t written = 0;
+ size_t len = count * 512;
+ ssize_t n;
+
+ fd_zero = open("/dev/zero", O_RDONLY);
+ if (fd_zero < 0) {
+ pr_err("Cannot open /dev/zero\n");
+ return -1;
+ }
+
+ if (lseek64(fd, sector * 512, SEEK_SET) < 0) {
+ ret = -errno;
+ pr_err("Failed to seek offset for zeroing\n");
+ goto out;
+ }
+
+ addr = mmap(NULL, len, PROT_READ, MAP_PRIVATE, fd_zero, 0);
+
+ if (addr == MAP_FAILED) {
+ ret = -errno;
+ pr_err("Mapping /dev/zero failed\n");
+ goto out;
+ }
+
+ do {
+ n = write(fd, addr + written, len - written);
+ if (n < 0) {
+ if (errno == EINTR)
+ continue;
+ ret = -errno;
+ pr_err("Zeroing disk range failed\n");
+ break;
+ }
+ written += n;
+ } while (written != len);
+
+ munmap(addr, len);
+
+out:
+ close(fd_zero);
+ return ret;
+}