xref: /kvmtool/disk/blk.c (revision 58fd2b7b2707f576f9fa6d5f9b6edaebbe51cf72)
1708dc6cbSAsias He #include "kvm/disk-image.h"
2708dc6cbSAsias He 
39f9207c5SSasha Levin #include <linux/err.h>
4*58fd2b7bSAsias He #include <mntent.h>
59f9207c5SSasha Levin 
6708dc6cbSAsias He /*
7708dc6cbSAsias He  * raw image and blk dev are similar, so reuse raw image ops.
8708dc6cbSAsias He  */
9063e87a0SAsias He static struct disk_image_operations blk_dev_ops = {
1087ee33c8SAsias He 	.read_sector	= raw_image__read_sector,
1187ee33c8SAsias He 	.write_sector	= raw_image__write_sector,
12708dc6cbSAsias He };
13708dc6cbSAsias He 
14*58fd2b7bSAsias He static bool is_mounted(struct stat *st)
15*58fd2b7bSAsias He {
16*58fd2b7bSAsias He 	struct stat st_buf;
17*58fd2b7bSAsias He 	struct mntent *mnt;
18*58fd2b7bSAsias He 	FILE *f;
19*58fd2b7bSAsias He 
20*58fd2b7bSAsias He 	f = setmntent("/proc/mounts", "r");
21*58fd2b7bSAsias He 	if (!f)
22*58fd2b7bSAsias He 		return false;
23*58fd2b7bSAsias He 
24*58fd2b7bSAsias He 	while ((mnt = getmntent(f)) != NULL) {
25*58fd2b7bSAsias He 		if (stat(mnt->mnt_fsname, &st_buf) == 0 &&
26*58fd2b7bSAsias He 		    S_ISBLK(st_buf.st_mode) && st->st_rdev == st_buf.st_rdev) {
27*58fd2b7bSAsias He 			fclose(f);
28*58fd2b7bSAsias He 			return true;
29*58fd2b7bSAsias He 		}
30*58fd2b7bSAsias He 	}
31*58fd2b7bSAsias He 
32*58fd2b7bSAsias He 	fclose(f);
33*58fd2b7bSAsias He 	return false;
34*58fd2b7bSAsias He }
35*58fd2b7bSAsias He 
36708dc6cbSAsias He struct disk_image *blkdev__probe(const char *filename, struct stat *st)
37708dc6cbSAsias He {
38*58fd2b7bSAsias He 	struct disk_image *disk;
399f9207c5SSasha Levin 	int fd, r;
40*58fd2b7bSAsias He 	u64 size;
41708dc6cbSAsias He 
42708dc6cbSAsias He 	if (!S_ISBLK(st->st_mode))
439f9207c5SSasha Levin 		return ERR_PTR(-EINVAL);
44708dc6cbSAsias He 
45*58fd2b7bSAsias He 	if (is_mounted(st)) {
46*58fd2b7bSAsias He 		pr_err("Block device %s is already mounted! Unmount before use.",
47*58fd2b7bSAsias He 		       filename);
48*58fd2b7bSAsias He 		return ERR_PTR(-EINVAL);
49*58fd2b7bSAsias He 	}
50*58fd2b7bSAsias He 
51063e87a0SAsias He 	/*
52063e87a0SAsias He 	 * Be careful! We are opening host block device!
53063e87a0SAsias He 	 * Open it readonly since we do not want to break user's data on disk.
54063e87a0SAsias He 	 */
55*58fd2b7bSAsias He 	fd = open(filename, O_RDWR);
56708dc6cbSAsias He 	if (fd < 0)
579f9207c5SSasha Levin 		return ERR_PTR(fd);
58708dc6cbSAsias He 
59708dc6cbSAsias He 	if (ioctl(fd, BLKGETSIZE64, &size) < 0) {
609f9207c5SSasha Levin 		r = -errno;
61708dc6cbSAsias He 		close(fd);
629f9207c5SSasha Levin 		return ERR_PTR(r);
63708dc6cbSAsias He 	}
64708dc6cbSAsias He 
65063e87a0SAsias He 	/*
66063e87a0SAsias He 	 * FIXME: This will not work on 32-bit host because we can not
67063e87a0SAsias He 	 * mmap large disk. There is not enough virtual address space
68063e87a0SAsias He 	 * in 32-bit host. However, this works on 64-bit host.
69063e87a0SAsias He 	 */
70*58fd2b7bSAsias He 	disk = disk_image__new(fd, size, &blk_dev_ops, DISK_IMAGE_REGULAR);
71*58fd2b7bSAsias He #ifdef CONFIG_HAS_AIO
72*58fd2b7bSAsias He 		if (!IS_ERR_OR_NULL(disk))
73*58fd2b7bSAsias He 			disk->async = 1;
74*58fd2b7bSAsias He #endif
75*58fd2b7bSAsias He 	return disk;
76708dc6cbSAsias He }
77