Partition size set to 0 when resizing extended and adding logical partition with BLKPG

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Hello,

I write to you because I believe that the BLKPG ioctl misbehaves when an
existing extended MBR partition is changed and a logical partition added
in it.
Should I report like this or should I sign up for bugzilla.kernel.org?

The /sys/block/sdx/sdxY/size entry is set to 0 and even opening the
extended partition fails.
This leads to e.g. udevd failing to have access.
https://github.com/storaged-project/udisks/issues/425

To fix this situation from userspace, a BLKRRPART ioctl is needed.

To reproduce it, I attached a small program, which you can run on this
prepared image or on any drive with a single extended partition on it.

$ wget http://kailueke.spline.de/test.img
$ udisksctl loop-setup -f test.img

$ sudo ./sim loop0
new size in /sys/block/loop0/loop0p1/size: 0
issuing BLKRRPART
new size in /sys/block/loop0/loop0p1/size: 2


Do you think that this should be fixed in the kernel?
Regards,
Kai Lüke

#include <errno.h>
#include <fcntl.h>
#include <linux/blkpg.h>
#include <linux/fs.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/ioctl.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>

int resizepart(char *path, int start, int fd) {
  struct blkpg_partition part;
  struct blkpg_ioctl_arg ioctl_arg;
  memset(&part, 0, sizeof(part));
  part.start = start;
  part.length = 1;
  part.pno = 1;
  strncpy(part.devname, path, BLKPG_DEVNAMELTH);
  ioctl_arg.op = BLKPG_RESIZE_PARTITION;
  ioctl_arg.flags = 0;
  ioctl_arg.datalen = sizeof(struct blkpg_partition);
  ioctl_arg.data = (void *)&part;
  if (ioctl(fd, BLKPG, &ioctl_arg) == -1) {
    perror(strerror(errno));
    exit(errno);
  }
}

int addpart(char *path, int start, int fd) {
  struct blkpg_partition part;
  struct blkpg_ioctl_arg ioctl_arg;
  memset(&part, 0, sizeof(part));
  part.start = start + 2097152;
  part.length = 10485760; /* 10 MB */
  part.pno = 5;
  strncpy(part.devname, path, BLKPG_DEVNAMELTH);
  ioctl_arg.op = BLKPG_ADD_PARTITION;
  ioctl_arg.flags = 0;
  ioctl_arg.datalen = sizeof(struct blkpg_partition);
  ioctl_arg.data = (void *)&part;
  if (ioctl(fd, BLKPG, &ioctl_arg) == -1) {
    perror(strerror(errno));
    exit(errno);
  }
}

int main(int argc, char **argv) {
  char *disk;
  char *existing_extended_part;
  char *new_logical_part;
  int fd;
  int read_fd;
  char path[100];
  char buf[100];
  int start;
  const char *loopback = "";
  if (argc != 2) {
    printf("Usage: %s sdb \nAnnounces a logical sdb5 partition to the kernel "
           "on MBR drive /dev/sdb, which must only have a single extended "
           "partition (sdb1) and no logical partitons present yet.\nThis is "
           "done with BLKPG calls to issue a resize call for sdb1 and an add "
           "call for sdb5.\nThe observed problem is that the kernel then has a "
           "zero size for the extended partition (thus, nothing can access it "
           "anymore). Only a BLKRRPART can fix it again, as will be done here "
           "when a zero size is detected.\n\nEven when the BLKRRPART is "
           "removed here,"
           "after this program ends, udev will anyway trigger a BLKRRPART,"
           "therefore, you may have to pause udevd if it is"
           "interfering with a command you want to run afterwards:\n"
           "sudo kill -s STOP `pgrep udevd`\nThen, after running all you "
           "commands, "
           "you can continue udevd again:\nsudo kill -s CONT `pgrep udevd`",
           argv[0]);
    return -1;
  }
  disk = argv[1];
  if (strncmp(disk, "loop", 4) == 0)
    loopback = "p";
  memset(path, 0, sizeof(path));
  snprintf(path, sizeof(path), "/sys/block/%s/%s%s1/start", disk, disk,
           loopback);
  read_fd = open(path, O_RDONLY);
  if (read_fd == -1) {
    perror(strerror(errno));
    exit(errno);
  }
  memset(buf, 0, sizeof(buf));
  if (read(read_fd, buf, sizeof(buf)) == -1)
    return -1;
  close(read_fd);
  start = atoi(buf) * 512;
  memset(path, 0, sizeof(path));
  snprintf(path, sizeof(path), "/dev/%s", disk);
  fd = open(path, O_RDWR);
  if (fd == -1) {
    perror(strerror(errno));
    exit(errno);
  }
  /* order can be reversed to add/resize and the result is still the same:
   * /sys/block/sdb/sdb1/size containing a 0 instead of 1 or 2 */

  memset(path, 0, sizeof(path));
  snprintf(path, sizeof(path), "/dev/%s%s1", disk, loopback);
  resizepart(path, start, fd);

  memset(path, 0, sizeof(path));
  snprintf(path, sizeof(path), "/dev/%s%s5", disk, loopback);
  addpart(path, start, fd);

  /* even adding this again as last step does not help */
  memset(path, 0, sizeof(path));
  snprintf(path, sizeof(path), "/dev/%s%s1", disk, loopback);
  resizepart(path, start, fd);

  /* fetch value now for convenience and also because no interfering BLKRRPART
   * was done yet by other programs */
  memset(path, 0, sizeof(path));
  snprintf(path, sizeof(path), "/sys/block/%s/%s%s1/size", disk, disk,
           loopback);
  while (1) {
    memset(buf, 0, sizeof(buf));
    read_fd = open(path, O_RDONLY);
    if (read_fd == -1 || read(read_fd, buf, sizeof(buf)) == -1) {
      printf("could not fetch %s\n", path);
      if (read_fd != -1)
        close(read_fd);
      perror(strerror(errno));
      exit(errno);
    }
    close(read_fd);
    printf("new size in %s: %s\n", path, buf);
    if (atoi(buf) != 0) {
      break;
    }
    ioctl(fd, BLKRRPART, 0);
    printf("issuing BLKRRPART\n");
  }
  close(fd);
  return 0;
}
--
dm-devel mailing list
dm-devel@xxxxxxxxxx
https://www.redhat.com/mailman/listinfo/dm-devel

[Index of Archives]     [DM Crypt]     [Fedora Desktop]     [ATA RAID]     [Fedora Marketing]     [Fedora Packaging]     [Fedora SELinux]     [Yosemite Discussion]     [KDE Users]     [Fedora Docs]

  Powered by Linux