xref: /kvmtool/disk/blk.c (revision 2790307c3d6d2aad838e1eef76ec0aa21b110698)
1 #include "kvm/disk-image.h"
2 
3 #include <linux/err.h>
4 #include <mntent.h>
5 
6 /*
7  * raw image and blk dev are similar, so reuse raw image ops.
8  */
9 static struct disk_image_operations blk_dev_ops = {
10 	.read	= raw_image__read,
11 	.write	= raw_image__write,
12 	.wait	= raw_image__wait,
13 	.async	= true,
14 };
15 
is_mounted(struct stat * st)16 static bool is_mounted(struct stat *st)
17 {
18 	struct stat st_buf;
19 	struct mntent *mnt;
20 	FILE *f;
21 
22 	f = setmntent("/proc/mounts", "r");
23 	if (!f)
24 		return false;
25 
26 	while ((mnt = getmntent(f)) != NULL) {
27 		if (stat(mnt->mnt_fsname, &st_buf) == 0 &&
28 		    S_ISBLK(st_buf.st_mode) && st->st_rdev == st_buf.st_rdev) {
29 			fclose(f);
30 			return true;
31 		}
32 	}
33 
34 	fclose(f);
35 	return false;
36 }
37 
blkdev__probe(const char * filename,int flags,struct stat * st)38 struct disk_image *blkdev__probe(const char *filename, int flags, struct stat *st)
39 {
40 	int fd, r;
41 	u64 size;
42 
43 	if (!S_ISBLK(st->st_mode))
44 		return ERR_PTR(-EINVAL);
45 
46 	if (is_mounted(st)) {
47 		pr_err("Block device %s is already mounted! Unmount before use.",
48 		       filename);
49 		return ERR_PTR(-EINVAL);
50 	}
51 
52 	/*
53 	 * Be careful! We are opening host block device!
54 	 * Open it readonly since we do not want to break user's data on disk.
55 	 */
56 	fd = open(filename, flags);
57 	if (fd < 0)
58 		return ERR_PTR(fd);
59 
60 	if (ioctl(fd, BLKGETSIZE64, &size) < 0) {
61 		r = -errno;
62 		close(fd);
63 		return ERR_PTR(r);
64 	}
65 
66 	/*
67 	 * FIXME: This will not work on 32-bit host because we can not
68 	 * mmap large disk. There is not enough virtual address space
69 	 * in 32-bit host. However, this works on 64-bit host.
70 	 */
71 	return disk_image__new(fd, size, &blk_dev_ops, DISK_IMAGE_REGULAR);
72 }
73