/* libparted - a library for manipulating disk partitions
- Copyright (C) 1999 - 2005, 2007, 2008 Free Software Foundation, Inc.
+ Copyright (C) 1999-2011 Free Software Foundation, Inc.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
#define PROC_DEVICES_BUFSIZ 16384
#include <config.h>
-
+#include <arch/linux.h>
+#include <linux/blkpg.h>
#include <parted/parted.h>
#include <parted/debug.h>
-#include <parted/linux.h>
+#if defined __s390__ || defined __s390x__
+#include <parted/fdasd.h>
+#endif
#include <ctype.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/utsname.h> /* for uname() */
#include <scsi/scsi.h>
+#include <assert.h>
#ifdef ENABLE_DEVICE_MAPPER
#include <libdevmapper.h>
#endif
-#include "blkpg.h"
#include "../architecture.h"
+#include "dirname.h"
+#include "xstrtol.h"
#if ENABLE_NLS
# include <libintl.h>
#define HDIO_GETGEO 0x0301 /* get device geometry */
#define HDIO_GET_IDENTITY 0x030d /* get IDE identification info */
-#if defined(O_DIRECT) && !(defined(__s390__) || defined(__s390x__))
-#define RD_MODE (O_RDONLY | O_DIRECT)
-#define WR_MODE (O_WRONLY | O_DIRECT)
-#define RW_MODE (O_RDWR | O_DIRECT)
-#else
#define RD_MODE (O_RDONLY)
#define WR_MODE (O_WRONLY)
#define RW_MODE (O_RDWR)
-#endif
struct hd_geometry {
unsigned char heads;
#define SCSI_DISK5_MAJOR 69
#define SCSI_DISK6_MAJOR 70
#define SCSI_DISK7_MAJOR 71
+#define SCSI_DISK8_MAJOR 128
+#define SCSI_DISK9_MAJOR 129
+#define SCSI_DISK10_MAJOR 130
+#define SCSI_DISK11_MAJOR 131
+#define SCSI_DISK12_MAJOR 132
+#define SCSI_DISK13_MAJOR 133
+#define SCSI_DISK14_MAJOR 134
+#define SCSI_DISK15_MAJOR 135
#define COMPAQ_SMART2_MAJOR 72
#define COMPAQ_SMART2_MAJOR1 73
#define COMPAQ_SMART2_MAJOR2 74
#define UBD_MAJOR 98
#define DASD_MAJOR 94
#define VIODASD_MAJOR 112
+#define AOE_MAJOR 152
#define SX8_MAJOR1 160
#define SX8_MAJOR2 161
#define XVD_MAJOR 202
+#define SDMMC_MAJOR 179
+#define LOOP_MAJOR 7
+#define MD_MAJOR 9
#define SCSI_BLK_MAJOR(M) ( \
(M) == SCSI_DISK0_MAJOR \
|| (M) == SCSI_CDROM_MAJOR \
- || ((M) >= SCSI_DISK1_MAJOR && (M) <= SCSI_DISK7_MAJOR))
+ || ((M) >= SCSI_DISK1_MAJOR && (M) <= SCSI_DISK7_MAJOR) \
+ || ((M) >= SCSI_DISK8_MAJOR && (M) <= SCSI_DISK15_MAJOR))
+
+/* Maximum number of partitions supported by linux. */
+#define MAX_NUM_PARTS 64
static char* _device_get_part_path (PedDevice* dev, int num);
static int _partition_is_mounted_by_path (const char* path);
static int
-_is_ide_major (int major)
-{
- switch (major) {
- case IDE0_MAJOR:
- case IDE1_MAJOR:
- case IDE2_MAJOR:
- case IDE3_MAJOR:
- case IDE4_MAJOR:
- case IDE5_MAJOR:
- return 1;
-
- default:
- return 0;
- }
-}
-
-static int
-_is_cpqarray_major (int major)
-{
- return ((COMPAQ_SMART2_MAJOR <= major && major <= COMPAQ_SMART2_MAJOR7)
- || (COMPAQ_SMART_MAJOR <= major && major <= COMPAQ_SMART_MAJOR7));
-}
-
-static int
-_is_i2o_major (int major)
-{
- return (I2O_MAJOR1 <= major && major <= I2O_MAJOR8);
-}
-
-static int
-_is_sx8_major (int major)
-{
- return (SX8_MAJOR1 <= major && major <= SX8_MAJOR2);
-}
-
-#ifdef ENABLE_DEVICE_MAPPER
-static int
-_dm_maptype (PedDevice *dev)
-{
- LinuxSpecific* arch_specific = LINUX_SPECIFIC (dev);
- struct dm_task *dmt;
- void *next;
- uint64_t start, length;
- char *target_type = NULL;
- char *params;
- int r = -1;
- const char* dev_dir = getenv ("DM_DEV_DIR");
-
- if (dev_dir && *dev_dir && !dm_set_dev_dir(dev_dir))
- return r;
-
- if (!(dmt = dm_task_create(DM_DEVICE_TABLE)))
- return r;
-
- if (!dm_task_set_name(dmt, dev->path))
- goto bad;
-
- dm_task_no_open_count(dmt);
-
- if (!dm_task_run(dmt))
- goto bad;
-
- next = dm_get_next_target(dmt, NULL, &start, &length,
- &target_type, ¶ms);
-
- arch_specific->dmtype = strdup(target_type);
- if (arch_specific->dmtype == NULL)
- goto bad;
- r = 0;
-bad:
- dm_task_destroy(dmt);
- return r;
-}
-
-static int
-readFD (int fd, char **buf)
+_read_fd (int fd, char **buf)
{
char* p;
size_t size = PROC_DEVICES_BUFSIZ;
break;
filesize += s;
size += s;
- *buf = realloc (*buf, size);
+ char *new_buf = realloc (*buf, size);
+ if (new_buf == NULL) {
+ int saved_errno = errno;
+ free (*buf);
+ errno = saved_errno;
+ return -1;
+ }
+ *buf = new_buf;
} while (1);
if (filesize == 0 && s < 0) {
*buf = NULL;
return -1;
} else {
- /* there is always some excess memory left unused */
- *buf = realloc (*buf, filesize+1);
+ char *new_buf = realloc (*buf, filesize + 1);
+ if (new_buf == NULL) {
+ int saved_errno = errno;
+ free (*buf);
+ errno = saved_errno;
+ return -1;
+ }
+ *buf = new_buf;
(*buf)[filesize] = '\0';
}
}
static int
-_is_dm_major (int major)
+_major_type_in_devices (int major, const char* type)
{
int fd;
char* buf = NULL;
if (fd < 0)
return 0;
- if (readFD(fd, &buf) < 0) {
+ if (_read_fd(fd, &buf) < 0) {
close(fd);
return 0;
}
}
name = strrchr(line, ' ');
- if (!name || strcmp(name+1, "device-mapper"))
+ if (!name || strcmp(name+1, type))
goto next;
maj = strtol(line, &name, 10);
}
static int
+_is_ide_major (int major)
+{
+ switch (major) {
+ case IDE0_MAJOR:
+ case IDE1_MAJOR:
+ case IDE2_MAJOR:
+ case IDE3_MAJOR:
+ case IDE4_MAJOR:
+ case IDE5_MAJOR:
+ return 1;
+
+ default:
+ return 0;
+ }
+}
+
+static int
+_is_cpqarray_major (int major)
+{
+ return ((COMPAQ_SMART2_MAJOR <= major && major <= COMPAQ_SMART2_MAJOR7)
+ || (COMPAQ_SMART_MAJOR <= major && major <= COMPAQ_SMART_MAJOR7));
+}
+
+static int
+_is_i2o_major (int major)
+{
+ return (I2O_MAJOR1 <= major && major <= I2O_MAJOR8);
+}
+
+static int
+_is_sx8_major (int major)
+{
+ return (SX8_MAJOR1 <= major && major <= SX8_MAJOR2);
+}
+
+static int
+_is_virtblk_major (int major)
+{
+ return _major_type_in_devices (major, "virtblk");
+}
+
+#ifdef ENABLE_DEVICE_MAPPER
+static int
+_is_dm_major (int major)
+{
+ return _major_type_in_devices (major, "device-mapper");
+}
+
+static int
+_dm_maptype (PedDevice *dev)
+{
+ LinuxSpecific* arch_specific = LINUX_SPECIFIC (dev);
+ struct dm_task *dmt;
+ uint64_t start, length;
+ char *target_type = NULL;
+ char *params;
+ int r = -1;
+ const char* dev_dir = getenv ("DM_DEV_DIR");
+
+ if (dev_dir && *dev_dir && !dm_set_dev_dir(dev_dir))
+ return r;
+
+ if (!(dmt = dm_task_create(DM_DEVICE_TABLE)))
+ return r;
+
+ if (!dm_task_set_major_minor(dmt, arch_specific->major,
+ arch_specific->minor, 0))
+ goto bad;
+
+ dm_task_no_open_count(dmt);
+
+ if (!dm_task_run(dmt))
+ goto bad;
+
+ dm_get_next_target(dmt, NULL, &start, &length, &target_type, ¶ms);
+
+ arch_specific->dmtype = strdup(target_type ? target_type : "NO-TARGET");
+ if (arch_specific->dmtype == NULL)
+ goto bad;
+ r = 0;
+bad:
+ dm_task_destroy(dmt);
+ return r;
+}
+
+
+static int
_probe_dm_devices ()
{
DIR* mapper_dir;
static int
_device_stat (PedDevice* dev, struct stat * dev_stat)
{
- PED_ASSERT (dev != NULL, return 0);
- PED_ASSERT (!dev->external_mode, return 0);
+ PED_ASSERT (dev != NULL);
+ PED_ASSERT (!dev->external_mode);
while (1) {
if (!stat (dev->path, dev_stat)) {
struct stat dev_stat;
int dev_major;
int dev_minor;
+ LinuxSpecific* arch_specific = LINUX_SPECIFIC (dev);
if (!_device_stat (dev, &dev_stat))
return 0;
return 1;
}
- dev_major = major (dev_stat.st_rdev);
- dev_minor = minor (dev_stat.st_rdev);
+ arch_specific->major = dev_major = major (dev_stat.st_rdev);
+ arch_specific->minor = dev_minor = minor (dev_stat.st_rdev);
if (SCSI_BLK_MAJOR (dev_major) && (dev_minor % 0x10 == 0)) {
dev->type = PED_DEVICE_SCSI;
dev->type = PED_DEVICE_DAC960;
} else if (dev_major == ATARAID_MAJOR && (dev_minor % 0x10 == 0)) {
dev->type = PED_DEVICE_ATARAID;
+ } else if (dev_major == AOE_MAJOR && (dev_minor % 0x10 == 0)) {
+ dev->type = PED_DEVICE_AOE;
} else if (dev_major == DASD_MAJOR && (dev_minor % 0x4 == 0)) {
dev->type = PED_DEVICE_DASD;
} else if (dev_major == VIODASD_MAJOR && (dev_minor % 0x8 == 0)) {
#endif
} else if (dev_major == XVD_MAJOR && (dev_minor % 0x10 == 0)) {
dev->type = PED_DEVICE_XVD;
+ } else if (dev_major == SDMMC_MAJOR && (dev_minor % 0x08 == 0)) {
+ dev->type = PED_DEVICE_SDMMC;
+ } else if (_is_virtblk_major(dev_major)) {
+ dev->type = PED_DEVICE_VIRTBLK;
+ } else if (dev_major == LOOP_MAJOR) {
+ dev->type = PED_DEVICE_FILE;
+ } else if (dev_major == MD_MAJOR) {
+ dev->type = PED_DEVICE_MD;
} else {
dev->type = PED_DEVICE_UNKNOWN;
}
}
static int
-_have_devfs ()
+_have_kern26 ()
{
- static int have_devfs = -1;
- struct stat sb;
+ static int have_kern26 = -1;
+ int kver;
- if (have_devfs != -1)
- return have_devfs;
+ if (have_kern26 != -1)
+ return have_kern26;
- /* the presence of /dev/.devfsd implies that DevFS is active */
- if (stat("/dev/.devfsd", &sb) < 0)
- return have_devfs = 0;
+ kver = _get_linux_version();
+ return have_kern26 = kver >= KERNEL_VERSION (2,6,0) ? 1 : 0;
+}
+
+#if USE_BLKID
+static void
+get_blkid_topology (LinuxSpecific *arch_specific)
+{
+ arch_specific->probe = blkid_new_probe ();
+ if (!arch_specific->probe)
+ return;
- return have_devfs = S_ISCHR(sb.st_mode) ? 1 : 0;
+ if (blkid_probe_set_device(arch_specific->probe,
+ arch_specific->fd, 0, 0))
+ return;
+
+ arch_specific->topology =
+ blkid_probe_get_topology(arch_specific->probe);
}
+#endif
-static void
+static void
_device_set_sector_size (PedDevice* dev)
{
LinuxSpecific* arch_specific = LINUX_SPECIFIC (dev);
int sector_size;
-
+
dev->sector_size = PED_SECTOR_SIZE_DEFAULT;
dev->phys_sector_size = PED_SECTOR_SIZE_DEFAULT;
- PED_ASSERT (dev->open_count, return);
+ PED_ASSERT (dev->open_count);
if (_get_linux_version() < KERNEL_VERSION (2,3,0)) {
dev->sector_size = PED_SECTOR_SIZE_DEFAULT;
return;
}
-
+
if (ioctl (arch_specific->fd, BLKSSZGET, §or_size)) {
ped_exception_throw (
PED_EXCEPTION_WARNING,
dev->path, strerror (errno), PED_SECTOR_SIZE_DEFAULT);
} else {
dev->sector_size = (long long)sector_size;
+ dev->phys_sector_size = dev->sector_size;
}
- /* Return PED_SECTOR_SIZE_DEFAULT for DASDs. */
- if (dev->type == PED_DEVICE_DASD) {
- dev->sector_size = PED_SECTOR_SIZE_DEFAULT;
+#if USE_BLKID
+ get_blkid_topology(arch_specific);
+ if (!arch_specific->topology) {
+ dev->phys_sector_size = 0;
+ } else {
+ dev->phys_sector_size =
+ blkid_topology_get_physical_sector_size(
+ arch_specific->topology);
}
-
- if (dev->sector_size != PED_SECTOR_SIZE_DEFAULT) {
+ if (dev->phys_sector_size == 0) {
ped_exception_throw (
PED_EXCEPTION_WARNING,
PED_EXCEPTION_OK,
- _("Device %s has a logical sector size of %lld. Not "
- "all parts of GNU Parted support this at the moment, "
- "and the working code is HIGHLY EXPERIMENTAL.\n"),
+ _("Could not determine physical sector size for %s.\n"
+ "Using the logical sector size (%lld)."),
dev->path, dev->sector_size);
+ dev->phys_sector_size = dev->sector_size;
+ }
+#endif
+
+#if defined __s390__ || defined __s390x__
+ /* Return PED_SECTOR_SIZE_DEFAULT for DASDs. */
+ if (dev->type == PED_DEVICE_DASD) {
+ arch_specific->real_sector_size = dev->sector_size;
+ dev->sector_size = PED_SECTOR_SIZE_DEFAULT;
}
+#endif
}
static int
unsigned long size;
LinuxSpecific* arch_specific = LINUX_SPECIFIC (dev);
uint64_t bytes=0;
+ const char* test_str;
+ PedSector test_size;
+
+ PED_ASSERT (dev->open_count > 0);
+ PED_ASSERT (dev->sector_size % PED_SECTOR_SIZE_DEFAULT == 0);
- PED_ASSERT (dev->open_count > 0, return 0);
- PED_ASSERT (dev->sector_size % PED_SECTOR_SIZE_DEFAULT == 0, return 0);
+ test_str = getenv ("PARTED_TEST_DEVICE_LENGTH");
+ if (test_str
+ && xstrtoll (test_str, NULL, 10, &test_size, NULL) == LONGINT_OK)
+ return test_size;
if (_kernel_has_blkgetsize64()) {
if (ioctl(arch_specific->fd, BLKGETSIZE64, &bytes) == 0) {
if (!_device_stat (dev, &dev_stat))
return 0;
- PED_ASSERT (S_ISBLK (dev_stat.st_mode), return 0);
+ PED_ASSERT (S_ISBLK (dev_stat.st_mode));
_device_set_sector_size (dev);
-
+
dev->length = _device_get_length (dev);
if (!dev->length)
return 0;
{
LinuxSpecific* arch_specific = LINUX_SPECIFIC (dev);
struct stat dev_stat;
- int dev_major;
struct hd_driveid hdi;
PedExceptionOption ex_status;
char hdi_buf[41];
int sector_multiplier = 0;
-
+
if (!_device_stat (dev, &dev_stat))
goto error;
- dev_major = major (dev_stat.st_rdev);
-
if (!ped_device_open (dev))
goto error;
dev->model = strdup(_("Generic IDE"));
break;
default:
- PED_ASSERT (0, (void) 0);
+ PED_ASSERT (0);
break;
}
} else {
memcpy (hdi_buf, hdi.model, 40);
hdi_buf[40] = '\0';
dev->model = strip_name (hdi_buf);
-
+
if (!hdi.ata7_sectinfo.valid1 && hdi.ata7_sectinfo.valid2)
sector_multiplier = hdi.ata7_sectinfo.multiplier;
else
sector_multiplier = 1;
-
+
if (sector_multiplier != 1) {
ex_status = ped_exception_throw (
PED_EXCEPTION_WARNING,
"Please consult the web site for up-to-date "
"information."),
dev->path, sector_multiplier);
-
+
switch (ex_status) {
case PED_EXCEPTION_CANCEL:
goto error_close_dev;
case PED_EXCEPTION_IGNORE:
break;
default:
- PED_ASSERT (0, (void) 0);
+ PED_ASSERT (0);
break;
}
}
-
+
/* XXX sector_size has not been set yet! */
/* dev->phys_sector_size = dev->sector_size
* sector_multiplier;*/
char buf[256];
snprintf (name_buf, 127, "/sys/block/%s/device/%s",
- basename (dev->path), file);
+ last_component (dev->path), file);
if ((f = fopen (name_buf, "r")) == NULL)
return NULL;
init_file (PedDevice* dev)
{
struct stat dev_stat;
-
+
if (!_device_stat (dev, &dev_stat))
goto error;
if (!ped_device_open (dev))
goto error;
+ dev->sector_size = PED_SECTOR_SIZE_DEFAULT;
+ char *p = getenv ("PARTED_SECTOR_SIZE");
+ if (p) {
+ int s = atoi (p);
+ if (0 < s && s % 512 == 0)
+ dev->sector_size = s;
+ }
+ dev->phys_sector_size = dev->sector_size;
+
if (S_ISBLK(dev_stat.st_mode))
dev->length = _device_get_length (dev);
else
- dev->length = dev_stat.st_size / 512;
+ dev->length = dev_stat.st_size / dev->sector_size;
if (dev->length <= 0) {
ped_exception_throw (
PED_EXCEPTION_ERROR,
dev->bios_geom.heads = 4;
dev->bios_geom.sectors = 32;
dev->hw_geom = dev->bios_geom;
- dev->sector_size = PED_SECTOR_SIZE_DEFAULT;
- dev->phys_sector_size = PED_SECTOR_SIZE_DEFAULT;
dev->model = strdup ("");
-
+
return 1;
-
+
error_close_dev:
ped_device_close (dev);
error:
return 0;
}
+#if defined __s390__ || defined __s390x__
static int
init_dasd (PedDevice* dev, const char* model_name)
{
struct stat dev_stat;
struct hd_geometry geo;
- char *errstr = 0;
+ dasd_information_t dasd_info;
if (!_device_stat (dev, &dev_stat))
goto error;
LinuxSpecific* arch_specific = LINUX_SPECIFIC (dev);
- PED_ASSERT (S_ISBLK (dev_stat.st_mode), return 0);
+ PED_ASSERT (S_ISBLK (dev_stat.st_mode));
_device_set_sector_size (dev);
if (!dev->sector_size)
dev->hw_geom = dev->bios_geom;
}
+ if (!ioctl(arch_specific->fd, BIODASDINFO, &dasd_info)) {
+ arch_specific->devno = dasd_info.devno;
+ } else {
+ arch_specific->devno = arch_specific->major * 256 +
+ arch_specific->minor;
+ }
+
dev->model = strdup (model_name);
ped_device_close (dev);
return 1;
- ped_exception_throw ( PED_EXCEPTION_ERROR,
- PED_EXCEPTION_IGNORE_CANCEL,
- errstr );
-
error_close_dev:
ped_device_close (dev);
error:
return 0;
}
+#endif
static int
init_generic (PedDevice* dev, const char* model_name)
if (_device_probe_geometry (dev)) {
ped_exception_leave_all ();
} else {
+ if (!_device_get_length (dev)) {
+ ped_exception_catch ();
+ ped_exception_leave_all ();
+ goto error_close_dev;
+ }
+
/* hack to allow use of files, for testing */
ped_exception_catch ();
ped_exception_leave_all ();
case PED_EXCEPTION_IGNORE:
break;
default:
- PED_ASSERT (0, (void) 0);
+ PED_ASSERT (0);
break;
}
return 0;
}
+static int
+sdmmc_get_product_info (PedDevice* dev, char **type, char **name)
+{
+ *type = read_device_sysfs_file (dev, "type");
+ *name = read_device_sysfs_file (dev, "name");
+ if (*type && *name)
+ return 1;
+
+ return 0;
+}
+
+static int
+init_sdmmc (PedDevice* dev)
+{
+ char id[128];
+ char *type, *name;
+
+ if (sdmmc_get_product_info (dev, &type, &name)) {
+ snprintf (id, sizeof(id) - 1, "%s %s", type, name);
+ free (type);
+ free (name);
+ } else {
+ snprintf (id, sizeof(id) - 1, "%s",
+ _("Generic SD/MMC Storage Card"));
+ }
+ return init_generic(dev, id);
+}
+
static PedDevice*
linux_new (const char* path)
{
PedDevice* dev;
LinuxSpecific* arch_specific;
- PED_ASSERT (path != NULL, return NULL);
+ PED_ASSERT (path != NULL);
dev = (PedDevice*) ped_malloc (sizeof (PedDevice));
if (!dev)
goto error_free_path;
arch_specific = LINUX_SPECIFIC (dev);
arch_specific->dmtype = NULL;
+#if USE_BLKID
+ arch_specific->probe = NULL;
+ arch_specific->topology = NULL;
+#endif
dev->open_count = 0;
dev->read_only = 0;
goto error_free_arch_specific;
break;
+ case PED_DEVICE_AOE:
+ if (!init_generic (dev, _("ATA over Ethernet Device")))
+ goto error_free_arch_specific;
+ break;
+
+#if defined __s390__ || defined __s390x__
case PED_DEVICE_DASD:
if (!init_dasd (dev, _("IBM S390 DASD drive")))
goto error_free_arch_specific;
break;
+#endif
case PED_DEVICE_VIODASD:
if (!init_generic (dev, _("IBM iSeries Virtual DASD")))
goto error_free_arch_specific;
break;
+ case PED_DEVICE_SDMMC:
+ if (!init_sdmmc (dev))
+ goto error_free_arch_specific;
+ break;
+ case PED_DEVICE_VIRTBLK:
+ if (!init_generic(dev, _("Virtio Block Device")))
+ goto error_free_arch_specific;
+ break;
+
+ case PED_DEVICE_MD:
+ if (!init_generic(dev, _("Linux Software RAID Array")))
+ goto error_free_arch_specific;
+ break;
+
default:
ped_exception_throw (PED_EXCEPTION_NO_FEATURE,
PED_EXCEPTION_CANCEL,
static void
linux_destroy (PedDevice* dev)
{
- free (((LinuxSpecific*)dev->arch_specific)->dmtype);
+ LinuxSpecific *arch_specific = LINUX_SPECIFIC(dev);
+ void *p = arch_specific->dmtype;
+
+#if USE_BLKID
+ if (arch_specific->probe)
+ blkid_free_probe(arch_specific->probe);
+#endif
+ free (p);
free (dev->arch_specific);
free (dev->path);
free (dev->model);
return 0;
}
-/* we need to flush the master device, and all the partition devices,
- * because there is no coherency between the caches.
+/* we need to flush the master device, and with kernel < 2.6 all the partition
+ * devices, because there is no coherency between the caches with old kernels.
* We should only flush unmounted partition devices, because:
* - there is never a need to flush them (we're not doing IO there)
* - flushing a device that is mounted causes unnecessary IO, and can
ioctl (arch_specific->fd, BLKFLSBUF);
+ /* With linux-2.6.0 and newer, we're done. */
+ if (_have_kern26())
+ return;
+
for (i = 1; i < 16; i++) {
char* name;
int fd;
fd = open (name, WR_MODE, 0);
if (fd > 0) {
ioctl (fd, BLKFLSBUF);
- close (fd);
+retry:
+ if (fsync (fd) < 0 || close (fd) < 0)
+ if (ped_exception_throw (
+ PED_EXCEPTION_WARNING,
+ PED_EXCEPTION_RETRY +
+ PED_EXCEPTION_IGNORE,
+ _("Error fsyncing/closing %s: %s"),
+ name, strerror (errno))
+ == PED_EXCEPTION_RETRY)
+ goto retry;
}
}
free (name);
dev->read_only = 0;
}
- _flush_cache (dev);
+ /* With kernels < 2.6 flush cache for cache coherence issues */
+ if (!_have_kern26())
+ _flush_cache (dev);
return 1;
}
if (dev->dirty)
_flush_cache (dev);
- close (arch_specific->fd);
+retry:
+ if (fsync (arch_specific->fd) < 0 || close (arch_specific->fd) < 0)
+ if (ped_exception_throw (
+ PED_EXCEPTION_WARNING,
+ PED_EXCEPTION_RETRY + PED_EXCEPTION_IGNORE,
+ _("Error fsyncing/closing %s: %s"),
+ dev->path, strerror (errno))
+ == PED_EXCEPTION_RETRY)
+ goto retry;
return 1;
}
_device_seek (const PedDevice* dev, PedSector sector)
{
LinuxSpecific* arch_specific;
-
- PED_ASSERT (dev->sector_size % PED_SECTOR_SIZE_DEFAULT == 0, return 0);
- PED_ASSERT (dev != NULL, return 0);
- PED_ASSERT (!dev->external_mode, return 0);
-
+
+ PED_ASSERT (dev->sector_size % PED_SECTOR_SIZE_DEFAULT == 0);
+ PED_ASSERT (dev != NULL);
+ PED_ASSERT (!dev->external_mode);
+
arch_specific = LINUX_SPECIFIC (dev);
#if SIZEOF_OFF_T < 8
LinuxSpecific* arch_specific;
struct blkdev_ioctl_param ioctl_param;
- PED_ASSERT(dev != NULL, return 0);
- PED_ASSERT(buffer != NULL, return 0);
-
+ PED_ASSERT(dev != NULL);
+ PED_ASSERT(buffer != NULL);
+
arch_specific = LINUX_SPECIFIC (dev);
retry:
ioctl_param.block = 0; /* read the last sector */
ioctl_param.content_length = dev->sector_size;
ioctl_param.block_contents = buffer;
-
+
if (ioctl(arch_specific->fd, BLKGETLASTSECT, &ioctl_param) == -1) {
PedExceptionOption opt;
opt = ped_exception_throw (
PedExceptionOption ex_status;
void* diobuf = NULL;
- PED_ASSERT (dev != NULL, return 0);
- PED_ASSERT (dev->sector_size % PED_SECTOR_SIZE_DEFAULT == 0, return 0);
+ PED_ASSERT (dev != NULL);
+ PED_ASSERT (dev->sector_size % PED_SECTOR_SIZE_DEFAULT == 0);
if (_get_linux_version() < KERNEL_VERSION (2,6,0)) {
/* Kludge. This is necessary to read/write the last
case PED_EXCEPTION_CANCEL:
return 0;
default:
- PED_ASSERT (0, (void) 0);
+ PED_ASSERT (0);
break;
}
}
ex_status = ped_exception_throw (
PED_EXCEPTION_ERROR,
PED_EXCEPTION_RETRY_IGNORE_CANCEL,
- _("%s during read on %s"),
+ (status == 0
+ ? _("end of file while reading %s")
+ : _("%s during read on %s")),
strerror (errno),
dev->path);
free(diobuf);
return 0;
default:
- PED_ASSERT (0, (void) 0);
+ PED_ASSERT (0);
break;
}
}
LinuxSpecific* arch_specific;
struct blkdev_ioctl_param ioctl_param;
- PED_ASSERT(dev != NULL, return 0);
- PED_ASSERT(buffer != NULL, return 0);
-
+ PED_ASSERT(dev != NULL);
+ PED_ASSERT(buffer != NULL);
+
arch_specific = LINUX_SPECIFIC (dev);
retry:
ioctl_param.block = 0; /* write the last sector */
ioctl_param.content_length = dev->sector_size;
ioctl_param.block_contents = (void*) buffer;
-
+
if (ioctl(arch_specific->fd, BLKSETLASTSECT, &ioctl_param) == -1) {
PedExceptionOption opt;
opt = ped_exception_throw (
void* diobuf;
void* diobuf_start;
- PED_ASSERT(dev->sector_size % PED_SECTOR_SIZE_DEFAULT == 0, return 0);
+ PED_ASSERT(dev->sector_size % PED_SECTOR_SIZE_DEFAULT == 0);
if (dev->read_only) {
if (ped_exception_throw (
&& start + count - 1 == dev->length - 1)
return ped_device_write (dev, buffer, start, count - 1)
&& _write_lastoddsector (
- dev, (char*) buffer + (count-1) * 512);
+ dev, ((char*) buffer
+ + (count-1) * dev->sector_size));
}
while (1) {
if (_device_seek (dev, start))
case PED_EXCEPTION_CANCEL:
return 0;
default:
- PED_ASSERT (0, (void) 0);
+ PED_ASSERT (0);
break;
}
}
free(diobuf_start);
return 0;
default:
- PED_ASSERT (0, (void) 0);
+ PED_ASSERT (0);
break;
}
}
int status;
void* diobuf;
- PED_ASSERT(dev != NULL, return 0);
-
+ PED_ASSERT(dev != NULL);
+
if (!_device_seek (dev, start))
return 0;
case PED_EXCEPTION_CANCEL:
return 0;
default:
- PED_ASSERT (0, (void) 0);
+ PED_ASSERT (0);
break;
}
- }
+ }
return 1;
}
static int
linux_sync (PedDevice* dev)
{
- PED_ASSERT (dev != NULL, return 0);
- PED_ASSERT (!dev->external_mode, return 0);
+ PED_ASSERT (dev != NULL);
+ PED_ASSERT (!dev->external_mode);
if (dev->read_only)
return 1;
static int
linux_sync_fast (PedDevice* dev)
{
- PED_ASSERT (dev != NULL, return 0);
- PED_ASSERT (!dev->external_mode, return 0);
+ PED_ASSERT (dev != NULL);
+ PED_ASSERT (!dev->external_mode);
if (dev->read_only)
return 1;
}
_ped_device_probe (dev_name);
}
-
+
closedir (blockdir);
return 1;
}
_probe_proc_partitions ();
}
-static char*
-_device_get_part_path (PedDevice* dev, int num)
+static char * _GL_ATTRIBUTE_FORMAT ((__printf__, 1, 2))
+zasprintf (const char *format, ...)
{
- int path_len = strlen (dev->path);
- int result_len = path_len + 16;
- char* result;
+ va_list args;
+ char *resultp;
+ va_start (args, format);
+ int r = vasprintf (&resultp, format, args);
+ va_end (args);
+ return r < 0 ? NULL : resultp;
+}
- result = (char*) ped_malloc (result_len);
- if (!result)
- return NULL;
+static char*
+_device_get_part_path (PedDevice *dev, int num)
+{
+ size_t path_len = strlen (dev->path);
+ char *result;
/* Check for devfs-style /disc => /partN transformation
unconditionally; the system might be using udev with devfs rules,
and if not the test is harmless. */
- if (!strcmp (dev->path + path_len - 5, "/disc")) {
+ if (5 < path_len && !strcmp (dev->path + path_len - 5, "/disc")) {
/* replace /disc with /path%d */
- strcpy (result, dev->path);
- snprintf (result + path_len - 5, 16, "/part%d", num);
- } else if (dev->type == PED_DEVICE_DAC960
- || dev->type == PED_DEVICE_CPQARRAY
- || dev->type == PED_DEVICE_ATARAID
- || dev->type == PED_DEVICE_DM
- || isdigit (dev->path[path_len - 1]))
- snprintf (result, result_len, "%sp%d", dev->path, num);
- else
- snprintf (result, result_len, "%s%d", dev->path, num);
+ result = zasprintf ("%.*s/part%d",
+ (int) (path_len - 5), dev->path, num);
+ } else {
+ char const *p = (dev->type == PED_DEVICE_DAC960
+ || dev->type == PED_DEVICE_CPQARRAY
+ || dev->type == PED_DEVICE_ATARAID
+ || dev->type == PED_DEVICE_DM
+ || isdigit (dev->path[path_len - 1])
+ ? "p" : "");
+ result = zasprintf ("%s%s%d", dev->path, p, num);
+ }
return result;
}
struct stat dev_stat;
int dev_major, dev_minor;
- if (!_device_stat (part->disk->dev, &dev_stat))
+ if (stat (part->disk->dev->path, &dev_stat))
return (dev_t)0;
dev_major = major (dev_stat.st_rdev);
dev_minor = minor (dev_stat.st_rdev);
char line[512];
char part_name[512];
FILE* file;
- int junk;
file = fopen (file_name, "r");
if (!file)
return 0;
while (fgets (line, 512, file)) {
- junk = sscanf (line, "%s", part_name);
- if (stat (part_name, &part_stat) == 0) {
+ if (sscanf (line, "%s", part_name) == 1
+ && stat (part_name, &part_stat) == 0) {
if (part_stat.st_rdev == dev) {
fclose (file);
return 1;
if (!ped_partition_is_active (part))
return 0;
dev = _partition_get_part_dev (part);
+ if (!dev)
+ return 0;
return _partition_is_mounted_by_dev (dev);
}
static int
+_has_partitions (const PedDisk* disk)
+{
+ PED_ASSERT(disk != NULL);
+
+ /* Some devices can't be partitioned. */
+ if (!strcmp (disk->type->name, "loop"))
+ return 0;
+
+ return 1;
+}
+
+static int
linux_partition_is_busy (const PedPartition* part)
{
PedPartition* walk;
- PED_ASSERT (part != NULL, return 0);
+ PED_ASSERT (part != NULL);
if (_partition_is_mounted (part))
return 1;
}
static int
-_blkpg_add_partition (PedDisk* disk, PedPartition* part)
+_blkpg_add_partition (PedDisk* disk, const PedPartition *part)
{
struct blkpg_partition linux_part;
const char* vol_name;
char* dev_name;
- PED_ASSERT(disk != NULL, return 0);
- PED_ASSERT(disk->dev->sector_size % PED_SECTOR_SIZE_DEFAULT == 0,
- return 0);
+ PED_ASSERT(disk != NULL);
+ PED_ASSERT(disk->dev->sector_size % PED_SECTOR_SIZE_DEFAULT == 0);
+
+ if (!_has_partitions (disk))
+ return 0;
if (ped_disk_type_check_feature (disk->type,
PED_DISK_TYPE_PARTITION_NAME))
{
struct blkpg_partition linux_part;
+ if (!_has_partitions (disk))
+ return 0;
+
memset (&linux_part, 0, sizeof (linux_part));
linux_part.pno = n;
return _blkpg_part_command (disk->dev, &linux_part,
BLKPG_DEL_PARTITION);
}
+/*
+ * The number of partitions that a device can have depends on the kernel.
+ * If we don't find this value in /sys/block/DEV/range, we will use our own
+ * value.
+ */
+static unsigned int
+_device_get_partition_range(PedDevice* dev)
+{
+ int range, r;
+ char path[128];
+ FILE* fp;
+ bool ok;
+
+ r = snprintf(path, sizeof(path), "/sys/block/%s/range",
+ last_component(dev->path));
+ if (r < 0 || r >= sizeof(path))
+ return MAX_NUM_PARTS;
+
+ fp = fopen(path, "r");
+ if (!fp)
+ return MAX_NUM_PARTS;
+
+ ok = fscanf(fp, "%d", &range) == 1;
+ fclose(fp);
+
+ /* (range <= 0) is none sense.*/
+ return ok && range > 0 ? range : MAX_NUM_PARTS;
+}
+
+/*
+ * Sync the partition table in two step process:
+ * 1. Remove all of the partitions from the kernel's tables, but do not attempt
+ * removal of any partition for which the corresponding ioctl call fails.
+ * 2. Add all the partitions that we hold in disk, throwing a warning
+ * if we cannot because step 1 failed to remove it and it is not being
+ * added back with the same start and length.
+ *
+ * To achieve this two step process we must calculate the minimum number of
+ * maximum possible partitions between what linux supports and what the label
+ * type supports. EX:
+ *
+ * number=MIN(max_parts_supported_in_linux,max_parts_supported_in_msdos_tables)
+ */
static int
_disk_sync_part_table (PedDisk* disk)
{
- int i;
- int last = PED_MAX (ped_disk_get_last_partition_num (disk), 16);
- int* rets = ped_malloc(sizeof(int) * last);
- int* errnums = ped_malloc(sizeof(int) * last);
- int ret = 1;
+ PED_ASSERT(disk != NULL);
+ PED_ASSERT(disk->dev != NULL);
+ int lpn;
- for (i = 1; i <= last; i++) {
- rets[i - 1] = _blkpg_remove_partition (disk, i);
- errnums[i - 1] = errno;
- }
+ /* lpn = largest partition number. */
+ if (ped_disk_get_max_supported_partition_count(disk, &lpn))
+ lpn = PED_MIN(lpn, _device_get_partition_range(disk->dev));
+ else
+ lpn = _device_get_partition_range(disk->dev);
- for (i = 1; i <= last; i++) {
- PedPartition* part;
+ /* Its not possible to support largest_partnum < 0.
+ * largest_partnum == 0 would mean does not support partitions.
+ * */
+ if (lpn < 0)
+ return 0;
+ int ret = 0;
+ int *ok = calloc (lpn, sizeof *ok);
+ if (!ok)
+ return 0;
+ int *errnums = ped_malloc(sizeof(int) * lpn);
+ if (!errnums)
+ goto cleanup;
+
+ /* Attempt to remove each and every partition, retrying for
+ up to max_sleep_seconds upon any failure due to EBUSY. */
+ unsigned int sleep_microseconds = 10000;
+ unsigned int max_sleep_seconds = 1;
+ unsigned int n_sleep = (max_sleep_seconds
+ * 1000000 / sleep_microseconds);
+ int i;
+ for (i = 0; i < n_sleep; i++) {
+ if (i)
+ usleep (sleep_microseconds);
+ bool busy = false;
+ int j;
+ for (j = 0; j < lpn; j++) {
+ if (!ok[j]) {
+ ok[j] = _blkpg_remove_partition (disk, j + 1);
+ errnums[j] = errno;
+ if (!ok[j] && errnums[j] == EBUSY)
+ busy = true;
+ }
+ }
+ if (!busy)
+ break;
+ }
- part = ped_disk_get_partition (disk, i);
+ for (i = 1; i <= lpn; i++) {
+ const PedPartition *part = ped_disk_get_partition (disk, i);
if (part) {
- /* busy... so we won't (can't!) disturb ;) Prolly
- * doesn't matter anyway, because users shouldn't be
- * changing mounted partitions anyway...
- */
- if (!rets[i - 1] && errnums[i - 1] == EBUSY)
- continue;
+ if (!ok[i - 1] && errnums[i - 1] == EBUSY) {
+ struct hd_geometry geom;
+ unsigned long long length = 0;
+ /* get start and length of existing partition */
+ char *dev_name = _device_get_part_path (disk->dev, i);
+ if (!dev_name)
+ goto cleanup;
+ int fd = open (dev_name, O_RDONLY);
+ if (fd == -1
+ || ioctl (fd, HDIO_GETGEO, &geom)
+ || ioctl (fd, BLKGETSIZE64, &length)) {
+ ped_exception_throw (
+ PED_EXCEPTION_BUG,
+ PED_EXCEPTION_CANCEL,
+ _("Unable to determine the size and length of %s."),
+ dev_name);
+ if (fd != -1)
+ close (fd);
+ free (dev_name);
+ goto cleanup;
+ }
+ free (dev_name);
+ length /= disk->dev->sector_size;
+ close (fd);
+ if (geom.start == part->geom.start
+ && length == part->geom.length)
+ ok[i - 1] = 1;
+ /* If the new partition is unchanged and the
+ existing one was not removed because it was
+ in use, then reset the error flag and do not
+ try to add it since it is already there. */
+ continue;
+ }
/* add the (possibly modified or new) partition */
- if (!_blkpg_add_partition (disk, part))
- ret = 0;
+ if (!_blkpg_add_partition (disk, part)) {
+ ped_exception_throw (
+ PED_EXCEPTION_ERROR,
+ PED_EXCEPTION_RETRY_CANCEL,
+ _("Failed to add partition %d (%s)"),
+ i, strerror (errno));
+ goto cleanup;
+ }
}
}
+ char *bad_part_list = NULL;
+ /* now warn about any errors */
+ for (i = 1; i <= lpn; i++) {
+ if (ok[i - 1] || errnums[i - 1] == ENXIO)
+ continue;
+ if (bad_part_list == NULL) {
+ bad_part_list = malloc (lpn * 5);
+ if (!bad_part_list)
+ goto cleanup;
+ bad_part_list[0] = 0;
+ }
+ sprintf (bad_part_list + strlen (bad_part_list), "%d, ", i);
+ }
+ if (bad_part_list == NULL)
+ ret = 1;
+ else {
+ bad_part_list[strlen (bad_part_list) - 2] = 0;
+ if (ped_exception_throw (
+ PED_EXCEPTION_ERROR,
+ PED_EXCEPTION_IGNORE_CANCEL,
+ _("Partition(s) %s on %s have been written, but we have "
+ "been unable to inform the kernel of the change, "
+ "probably because it/they are in use. As a result, "
+ "the old partition(s) will remain in use. You "
+ "should reboot now before making further changes."),
+ bad_part_list, disk->dev->path) == PED_EXCEPTION_IGNORE)
+ ret = 1;
+ free (bad_part_list);
+ }
+ cleanup:
+ free (errnums);
+ free (ok);
return ret;
}
rc = dm_task_run(task);
dm_task_update_nodes();
dm_task_destroy(task);
- if (rc < 0)
+ if (!rc)
return 1;
return 0;
}
-static int
+static int
_dm_is_part (struct dm_info *this, char *name)
{
struct dm_task* task = NULL;
task = dm_task_create(DM_DEVICE_DEPS);
if (!task)
return 0;
-
+
dm_task_set_name(task, name);
- rc = dm_task_run(task);
- if (rc < 0) {
- rc = 0;
+ if (!dm_task_run(task))
goto err;
- }
- rc = 0;
memset(info, '\0', sizeof *info);
dm_task_get_info(task, info);
if (!deps)
goto err;
- rc = 0;
for (i = 0; i < deps->count; i++) {
unsigned int ma = major(deps->device[i]),
mi = minor(deps->device[i]);
static int
_dm_remove_parts (PedDevice* dev)
{
- struct stat dev_stat;
struct dm_task* task = NULL;
struct dm_info* info = alloca(sizeof *info);
struct dm_names* names = NULL;
unsigned int next = 0;
int rc;
-
- if (!_device_stat (dev, &dev_stat))
- goto err;
+ LinuxSpecific* arch_specific = LINUX_SPECIFIC (dev);
task = dm_task_create(DM_DEVICE_LIST);
if (!task)
goto err;
- dm_task_set_major (task, major (dev_stat.st_rdev));
- dm_task_set_minor (task, minor (dev_stat.st_rdev));
+ if (!dm_task_set_major_minor (task, arch_specific->major,
+ arch_specific->minor, 0))
+ goto err;
- rc = dm_task_run(task);
- if (rc < 0)
+ if (!dm_task_run(task))
goto err;
memset(info, '\0', sizeof *info);
rc = 0;
do {
- names = (void *)names + next;
+ names = (void *) ((char *) names + next);
if (_dm_is_part(info, names->name))
rc += _dm_remove_map_name(names->name);
static int
_dm_add_partition (PedDisk* disk, PedPartition* part)
{
- struct stat dev_stat;
- struct dm_task* task = NULL;
- int rc;
char* vol_name = NULL;
- char* dev_name = NULL;
+ const char* dev_name = NULL;
char* params = NULL;
+ LinuxSpecific* arch_specific = LINUX_SPECIFIC (disk->dev);
- dev_name = _device_get_part_path (disk->dev, part->num);
- if (!dev_name)
+ if (!_has_partitions(disk))
return 0;
- vol_name = strrchr (dev_name, '/');
- if (vol_name && *vol_name && *(++vol_name))
- vol_name = strdup (vol_name);
- else
- vol_name = strdup (dev_name);
- if (!vol_name)
- return 0;
+ /* Get map name from devicemapper */
+ struct dm_task *task = dm_task_create (DM_DEVICE_INFO);
+ if (!task)
+ goto err;
- if (!_device_stat (disk->dev, &dev_stat))
+ if (!dm_task_set_major_minor (task, arch_specific->major,
+ arch_specific->minor, 0))
goto err;
- if (asprintf (¶ms, "%d:%d %lld", major (dev_stat.st_rdev),
- minor (dev_stat.st_rdev), part->geom.start) == -1)
+ if (!dm_task_run(task))
+ goto err;
+
+ dev_name = dm_task_get_name (task);
+
+ if (asprintf (&vol_name, "%sp%d", dev_name, part->num) == -1)
goto err;
- if (!params)
+ /* Caution: dm_task_destroy frees dev_name. */
+ dm_task_destroy (task);
+ task = NULL;
+
+ if (asprintf (¶ms, "%d:%d %lld", arch_specific->major,
+ arch_specific->minor, part->geom.start) == -1)
goto err;
task = dm_task_create (DM_DEVICE_CREATE);
dm_task_set_name (task, vol_name);
dm_task_add_target (task, 0, part->geom.length,
"linear", params);
- rc = dm_task_run(task);
- if (rc >= 0) {
+ if (dm_task_run (task)) {
//printf("0 %ld linear %s\n", part->geom.length, params);
dm_task_update_nodes();
dm_task_destroy(task);
static int
_dm_reread_part_table (PedDisk* disk)
{
+ int largest_partnum = ped_disk_get_last_partition_num (disk);
+ if (largest_partnum <= 0)
+ return 1;
+
int rc = 1;
- int last = PED_MAX (ped_disk_get_last_partition_num (disk), 16);
+ int last = PED_MIN (largest_partnum, 16);
int i;
sync();
#endif
static int
-_kernel_reread_part_table (PedDevice* dev)
-{
- LinuxSpecific* arch_specific = LINUX_SPECIFIC (dev);
- int retry_count = 5;
-
- sync();
- while (ioctl (arch_specific->fd, BLKRRPART)) {
- retry_count--;
- sync();
- if (!retry_count) {
- ped_exception_throw (
- PED_EXCEPTION_WARNING,
- PED_EXCEPTION_IGNORE,
- _("The kernel was unable to re-read the partition "
- "table on %s (%s). This means Linux won't know "
- "anything about the modifications you made "
- "until you reboot. You should reboot your computer "
- "before doing anything with %s."),
- dev->path, strerror (errno), dev->path);
- return 0;
- }
- }
-
- return 1;
-}
-
-static int
_have_blkpg ()
{
static int have_blkpg = -1;
return have_blkpg = kver >= KERNEL_VERSION (2,4,0) ? 1 : 0;
}
+/* Return nonzero upon success, 0 if something fails. */
static int
linux_disk_commit (PedDisk* disk)
{
+ if (!_has_partitions (disk))
+ return 1;
+
#ifdef ENABLE_DEVICE_MAPPER
if (disk->dev->type == PED_DEVICE_DM)
return _dm_reread_part_table (disk);
#endif
if (disk->dev->type != PED_DEVICE_FILE) {
- /* The ioctl() command BLKPG_ADD_PARTITION does not notify
- * the devfs system; consequently, /proc/partitions will not
- * be up to date, and the proper links in /dev are not
- * created. Therefore, if using DevFS, we must get the kernel
- * to re-read and grok the partition table.
- */
- /* Work around kernel dasd problem so we really do BLKRRPART */
- if (disk->dev->type != PED_DEVICE_DASD &&
- _have_blkpg () && !_have_devfs ()) {
- if (_disk_sync_part_table (disk))
- return 1;
- }
- return _kernel_reread_part_table (disk->dev);
+ /* We now require BLKPG support. If this assertion fails,
+ please write to the mailing list describing your system.
+ Assuming it's never triggered, ...
+ FIXME: remove this assertion in 2012. */
+ assert (_have_blkpg ());
+
+ if (!_disk_sync_part_table (disk))
+ return 0;
}
return 1;
}
+#if USE_BLKID
+static PedAlignment*
+linux_get_minimum_alignment(const PedDevice *dev)
+{
+ blkid_topology tp = LINUX_SPECIFIC(dev)->topology;
+ if (!tp)
+ return NULL;
+
+ if (blkid_topology_get_minimum_io_size(tp) == 0)
+ return ped_alignment_new(
+ blkid_topology_get_alignment_offset(tp) /
+ dev->sector_size,
+ dev->phys_sector_size / dev->sector_size);
+
+ return ped_alignment_new(
+ blkid_topology_get_alignment_offset(tp) / dev->sector_size,
+ blkid_topology_get_minimum_io_size(tp) / dev->sector_size);
+}
+
+static PedAlignment*
+linux_get_optimum_alignment(const PedDevice *dev)
+{
+ blkid_topology tp = LINUX_SPECIFIC(dev)->topology;
+ if (!tp)
+ return NULL;
+
+ /* When PED_DEFAULT_ALIGNMENT is divisible by the *_io_size or
+ there are no *_io_size values, use the PED_DEFAULT_ALIGNMENT
+ If one or the other will not divide evenly, fall through to
+ previous logic. */
+ unsigned long optimal_io = blkid_topology_get_optimal_io_size(tp);
+ unsigned long minimum_io = blkid_topology_get_minimum_io_size(tp);
+ if (
+ (!optimal_io && !minimum_io)
+ || (optimal_io && PED_DEFAULT_ALIGNMENT % optimal_io == 0
+ && minimum_io && PED_DEFAULT_ALIGNMENT % minimum_io == 0)
+ || (!minimum_io && optimal_io
+ && PED_DEFAULT_ALIGNMENT % optimal_io == 0)
+ || (!optimal_io && minimum_io
+ && PED_DEFAULT_ALIGNMENT % minimum_io == 0)
+ ) {
+ /* DASD needs to use minimum alignment */
+ if (dev->type == PED_DEVICE_DASD)
+ return linux_get_minimum_alignment(dev);
+
+ return ped_alignment_new(
+ blkid_topology_get_alignment_offset(tp) / dev->sector_size,
+ PED_DEFAULT_ALIGNMENT / dev->sector_size);
+ }
+
+ /* If optimal_io_size is 0 and we don't meet the other criteria
+ for using the device.c default, return the minimum alignment. */
+ if (blkid_topology_get_optimal_io_size(tp) == 0)
+ return linux_get_minimum_alignment(dev);
+
+ return ped_alignment_new(
+ blkid_topology_get_alignment_offset(tp) / dev->sector_size,
+ blkid_topology_get_optimal_io_size(tp) / dev->sector_size);
+}
+#endif
+
static PedDeviceArchOps linux_dev_ops = {
_new: linux_new,
destroy: linux_destroy,
check: linux_check,
sync: linux_sync,
sync_fast: linux_sync_fast,
- probe_all: linux_probe_all
+ probe_all: linux_probe_all,
+#if USE_BLKID
+ get_minimum_alignment: linux_get_minimum_alignment,
+ get_optimum_alignment: linux_get_optimum_alignment,
+#endif
};
PedDiskArchOps linux_disk_ops = {