aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorUlf Lilleengen <lulf@FreeBSD.org>2008-09-07 13:54:57 +0000
committerUlf Lilleengen <lulf@FreeBSD.org>2008-09-07 13:54:57 +0000
commitf805f204b63aaab5b49c7371deb8c2fd015bd894 (patch)
tree16f2ffcdc41f0c11cebb1b3f34481ddf1a5d05cc
parent6f4745d5757e385b06448930a2570371eb2f9a1e (diff)
downloadsrc-f805f204b63aaab5b49c7371deb8c2fd015bd894.tar.gz
src-f805f204b63aaab5b49c7371deb8c2fd015bd894.zip
- Add a new ioctl for getting the provider name of a geom provider.
- Add a routine for looking up a device and checking if it is a valid geom provider given a partial or full path to its device node. Reviewed by: phk Approved by: pjd (mentor)
Notes
Notes: svn path=/head/; revision=182843
-rw-r--r--lib/libgeom/geom_util.c106
-rw-r--r--lib/libgeom/libgeom.h2
-rw-r--r--sys/geom/geom_dev.c7
-rw-r--r--sys/sys/disk.h6
4 files changed, 108 insertions, 13 deletions
diff --git a/lib/libgeom/geom_util.c b/lib/libgeom/geom_util.c
index c596178e5142..539b6c62dbb6 100644
--- a/lib/libgeom/geom_util.c
+++ b/lib/libgeom/geom_util.c
@@ -42,29 +42,22 @@ __FBSDID("$FreeBSD$");
#include <libgeom.h>
+static char *g_device_path_open(const char *, int *, int);
+
/*
* Open the given provider and at least check if this is a block device.
*/
int
g_open(const char *name, int dowrite)
{
- char path[MAXPATHLEN];
+ char *path;
int fd;
- if (name[0] == '/')
- strlcpy(path, name, sizeof(path));
- else
- snprintf(path, sizeof(path), "%s%s", _PATH_DEV, name);
-
- fd = open(path, dowrite ? O_RDWR : O_RDONLY);
+ path = g_device_path_open(name, &fd, dowrite);
+ if (path != NULL)
+ free(path);
if (fd == -1)
return (-1);
- /* Let try to get sectorsize, which will prove it is a GEOM provider. */
- if (g_sectorsize(fd) == -1) {
- close(fd);
- errno = EFTYPE;
- return (-1);
- }
return (fd);
}
@@ -121,6 +114,19 @@ g_sectorsize(int fd)
}
/*
+ * Return the correct provider name.
+ */
+char *
+g_providername(int fd)
+{
+ char name[MAXPATHLEN];
+
+ if (g_ioctl_arg(fd, DIOCGPROVIDERNAME, name) == -1)
+ return (NULL);
+ return (strdup(name));
+}
+
+/*
* Call BIO_FLUSH for the given provider.
*/
int
@@ -234,3 +240,77 @@ end:
}
return (fd);
}
+
+/*
+ * Return the device path device given a partial or full path to its node.
+ * A pointer can be provided, which will be set to an opened file descriptor of
+ * not NULL.
+ */
+static char *
+g_device_path_open(const char *devpath, int *fdp, int dowrite)
+{
+ char *path;
+ int fd;
+
+ /* Make sure that we can fail. */
+ if (fdp != NULL)
+ *fdp = -1;
+ /* Use the device node if we're able to open it. */
+ do {
+ fd = open(devpath, dowrite ? O_RDWR : O_RDONLY);
+ if (fd == -1)
+ break;
+ /*
+ * Let try to get sectorsize, which will prove it is a GEOM
+ * provider.
+ */
+ if (g_sectorsize(fd) == -1) {
+ close(fd);
+ errno = EFTYPE;
+ return (NULL);
+ }
+ if ((path = strdup(devpath)) == NULL) {
+ close(fd);
+ return (NULL);
+ }
+ if (fdp != NULL)
+ *fdp = fd;
+ else
+ close(fd);
+ return (path);
+ } while (0);
+
+ /* If we're not given an absolute path, assume /dev/ prefix. */
+ if (*devpath != '/') {
+ asprintf(&path, "%s%s", _PATH_DEV, devpath);
+ if (path == NULL)
+ return (NULL);
+ fd = open(path, dowrite ? O_RDWR : O_RDONLY);
+ if (fd == -1) {
+ free(path);
+ return (NULL);
+ }
+ /*
+ * Let try to get sectorsize, which will prove it is a GEOM
+ * provider.
+ */
+ if (g_sectorsize(fd) == -1) {
+ free(path);
+ close(fd);
+ errno = EFTYPE;
+ return (NULL);
+ }
+ if (fdp != NULL)
+ *fdp = fd;
+ else
+ close(fd);
+ return (path);
+ }
+ return (NULL);
+}
+
+char *
+g_device_path(const char *devpath)
+{
+ return (g_device_path_open(devpath, NULL, 0));
+}
diff --git a/lib/libgeom/libgeom.h b/lib/libgeom/libgeom.h
index 56736a36e2cc..7255bd4a8f31 100644
--- a/lib/libgeom/libgeom.h
+++ b/lib/libgeom/libgeom.h
@@ -154,6 +154,8 @@ int g_delete(int, off_t, off_t);
int g_get_ident(int, char *, size_t);
int g_get_name(const char *, char *, size_t);
int g_open_by_ident(const char *, int, char *, size_t);
+char *g_device_path(const char *);
+char *g_providername(int);
__END_DECLS
diff --git a/sys/geom/geom_dev.c b/sys/geom/geom_dev.c
index 4abbfc076904..eeb3b0932a48 100644
--- a/sys/geom/geom_dev.c
+++ b/sys/geom/geom_dev.c
@@ -244,6 +244,7 @@ g_dev_ioctl(struct cdev *dev, u_long cmd, caddr_t data, int fflag, struct thread
{
struct g_geom *gp;
struct g_consumer *cp;
+ struct g_provider *pp;
struct g_kerneldump kd;
off_t offset, length, chunk;
int i, error;
@@ -251,6 +252,7 @@ g_dev_ioctl(struct cdev *dev, u_long cmd, caddr_t data, int fflag, struct thread
gp = dev->si_drv1;
cp = dev->si_drv2;
+ pp = cp->provider;
error = 0;
KASSERT(cp->acr || cp->acw,
@@ -329,6 +331,11 @@ g_dev_ioctl(struct cdev *dev, u_long cmd, caddr_t data, int fflag, struct thread
case DIOCGIDENT:
error = g_io_getattr("GEOM::ident", cp, &i, data);
break;
+ case DIOCGPROVIDERNAME:
+ if (pp == NULL)
+ return (ENOENT);
+ strlcpy(data, pp->name, i);
+ break;
default:
if (cp->provider->geom->ioctl != NULL) {
diff --git a/sys/sys/disk.h b/sys/sys/disk.h
index 71e775e5e26f..4fe2e09c22f4 100644
--- a/sys/sys/disk.h
+++ b/sys/sys/disk.h
@@ -98,4 +98,10 @@ void disk_err(struct bio *bp, const char *what, int blkdone, int nl);
* - ident is optional and applications can't relay on its presence.
*/
+#define DIOCGPROVIDERNAME _IOR('d', 138, char[MAXPATHLEN])
+ /*-
+ * Store the provider name, given a device path, in a buffer. The buffer
+ * must be at least MAXPATHLEN bytes long.
+ */
+
#endif /* _SYS_DISK_H_ */