DragonFly submit List (threaded) for 2008-01
[
Date Prev][
Date Next]
[
Thread Prev][
Thread Next]
[
Date Index][
Thread Index]
vnconfig -l support patch (Re: vn(4) RFC Misc.)
Per my recent email to kernel@, Attached is a little patch to get
vnconfig to list configured / available vn devices adapted from
& imho improved from OpenBSD.
Unless there are objections, I'll probably commit within the next couple
of days - I had a couple of questions / notes though particularly
on the VNIOCGET ioctl kernel code:
- I'm implicitly trusting the input, assuming that this is
checked on kernel copy-in time. Is this a correct assumption
(I didn't have time to track it down)
- The 'struct vn_user' doesn't store the vn file path, so I use the
vfs cache to re-lookup the vnode pointer backing the VN -
is this silly?
Also, I'm not sure if I needed to lock anything before using
the vfs cache, so there might be problems there.
- I've not yet run this under jails, which may mean a path disclosure
problem. Suggestions on fixing this if it is an issue welcome.
- I wasn't quite sure on how to do the swap size calculation for swap
backed vns in some cases & got bored at that point. Should work for
the normal case. Yea, lame excuse, I know.
Tested briefly on a vmware UP VM & vkernel so far.
Next up: Add a mount_vnd interface to vnconfig, after which it
might make sense to move this piece into /usr/src/sbin
instead of usr.sbin.
Index: sys/dev/disk/vn/vn.c
===================================================================
RCS file: /home/dcvs/src/sys/dev/disk/vn/vn.c,v
retrieving revision 1.35
diff -u -r1.35 vn.c
--- sys/dev/disk/vn/vn.c 19 May 2007 20:31:16 -0000 1.35
+++ sys/dev/disk/vn/vn.c 8 Jan 2008 16:38:44 -0000
@@ -140,6 +140,7 @@
static int vnsetcred (struct vn_softc *vn, struct ucred *cred);
static void vnclear (struct vn_softc *vn);
+static int vnget (cdev_t dev, struct vn_softc *vn , struct vn_user *vnu);
static int vn_modevent (module_t, int, void *);
static int vniocattach_file (struct vn_softc *, struct vn_ioctl *, cdev_t dev, int flag, struct ucred *cred);
static int vniocattach_swap (struct vn_softc *, struct vn_ioctl *, cdev_t dev, int flag, struct ucred *cred);
@@ -457,6 +458,7 @@
case VNIOCDETACH:
case VNIOCGSET:
case VNIOCGCLEAR:
+ case VNIOCGET:
case VNIOCUSET:
case VNIOCUCLEAR:
goto vn_specific;
@@ -511,6 +513,10 @@
kprintf("vnioctl: CLRed\n");
break;
+ case VNIOCGET:
+ error = vnget(dev, vn, (struct vn_user *) ap->a_data);
+ break;
+
case VNIOCGSET:
vn_options |= *f;
*f = vn_options;
@@ -760,6 +766,88 @@
vn->sc_size = 0;
}
+/*
+ * vnget:
+ *
+ * populate a struct vn_user for the VNIOCGET ioctl.
+ * interface conventions defined in sys/sys/vnioctl.h.
+ */
+
+static int
+vnget(cdev_t dev, struct vn_softc *vn, struct vn_user *vnu)
+{
+ int error, found = 0;
+ char *freepath, *fullpath;
+ struct namecache *ncp;
+ struct nchandle nch;
+ struct vattr vattr;
+
+ if (vnu->vnu_unit == -1) {
+ vnu->vnu_unit = dkunit(dev);
+ }
+ else if (vnu->vnu_unit < 0)
+ return (EINVAL);
+
+ SLIST_FOREACH(vn, &vn_list, sc_list) {
+
+ if(vn->sc_unit != vnu->vnu_unit)
+ continue;
+
+ found = 1;
+
+ if (vn->sc_flags & VNF_INITED && vn->sc_vp != NULL) {
+
+ /* note: u_cred checked in vnioctl above */
+ error = VOP_GETATTR(vn->sc_vp, &vattr);
+ if (error)
+ return (error);
+
+ /* vfs_cache.c:vn_fullpath expects valid proc */
+ TAILQ_FOREACH(ncp, &vn->sc_vp->v_namecache, nc_vnode) {
+ if (ncp->nc_nlen)
+ break;
+ }
+ if (ncp == NULL)
+ return (EINVAL); /* panic ? */
+
+ nch.ncp = ncp;
+ nch.mount = vn->sc_vp->v_mount;
+ error = cache_fullpath(NULL, &nch,
+ &fullpath, &freepath);
+
+ if (error) {
+ kprintf("vnget: unable to resolve vp %p\n",
+ vn->sc_vp);
+ return(error);
+ }
+
+ strlcpy(vnu->vnu_file, fullpath,
+ sizeof(vnu->vnu_file));
+ kfree(freepath, M_TEMP);
+ vnu->vnu_dev = vattr.va_fsid;
+ vnu->vnu_ino = vattr.va_fileid;
+
+ }
+ else if (vn->sc_flags & VNF_INITED && vn->sc_object != NULL){
+
+ strlcpy(vnu->vnu_file, _VN_USER_SWAP,
+ sizeof(vnu->vnu_file));
+ vnu->vnu_size = vn->sc_size;
+ vnu->vnu_secsize = vn->sc_secsize;
+ } else {
+ bzero(vnu->vnu_file, sizeof(vnu->vnu_file));
+ vnu->vnu_dev = 0;
+ vnu->vnu_ino = 0;
+ }
+ break;
+ }
+
+ if (!found)
+ return(ENXIO);
+
+ return(0);
+}
+
static int
vnsize(struct dev_psize_args *ap)
{
Index: sys/sys/vnioctl.h
===================================================================
RCS file: /home/dcvs/src/sys/sys/vnioctl.h,v
retrieving revision 1.3
diff -u -r1.3 vnioctl.h
--- sys/sys/vnioctl.h 15 May 2007 22:44:19 -0000 1.3
+++ sys/sys/vnioctl.h 8 Jan 2008 00:26:54 -0000
@@ -46,6 +46,10 @@
#ifndef _SYS_VNIOCTL_H_
#define _SYS_VNIOCTL_H_
+#ifndef _SYS_PARAMH_H_
+#include <sys/param.h> /* PATH_MAX */
+#endif
+
/*
* Ioctl definitions for file (vnode) disk pseudo-device.
*/
@@ -58,6 +62,39 @@
};
/*
+ * Structure used by userland to query vn devices.
+ *
+ * In file-backed configurations, vnu_file will contain the full path to
+ * the backing file, with vnu_dev and vnu_ino pointing to the appropriate
+ * filesystem entries for that file.
+ *
+ * In swap-backed configurations, vnu_file will contain the token "swap",
+ * with vnu_size and vnu_secsize indicating the portion of virtual memory
+ * in use by the vnode disk.
+ *
+ * Todo: verify vnu_file within a jail - path disclosure problem ?
+ */
+
+
+struct vn_user {
+ int vnu_unit; /* vn unit */
+ char vnu_file[PATH_MAX]; /* vn description */
+#define _VN_USER_SWAP "swap" /* indicates swap-backed vn */
+ union {
+ dev_t dev; /* vn device */
+ u_int64_t size; /* size per vnu_secsize */
+ } data1;
+ union {
+ ino_t ino; /* vn inode */
+ int secsize; /* sector size */
+ } data2;
+};
+#define vnu_dev data1.dev
+#define vnu_size data1.size
+#define vnu_ino data2.ino
+#define vnu_secsize data2.secsize
+
+/*
* Before you can use a unit, it must be configured with VNIOCSET.
* The configuration persists across opens and closes of the device;
* an VNIOCCLR must be used to reset a configuration. An attempt to
@@ -69,6 +106,7 @@
#define VNIOCGCLEAR _IOWR('F', 3, u_long ) /* reset --//-- */
#define VNIOCUSET _IOWR('F', 4, u_long ) /* set unit option */
#define VNIOCUCLEAR _IOWR('F', 5, u_long ) /* reset --//-- */
+#define VNIOCGET _IOWR('F', 6, struct vn_user) /* get disk info */
#define VN_LABELS 0x1 /* Use disk(/slice) labels */
#define VN_FOLLOW 0x2 /* Debug flow in vn driver */
Index: usr.sbin/vnconfig/vnconfig.8
===================================================================
RCS file: /home/dcvs/src/usr.sbin/vnconfig/vnconfig.8,v
retrieving revision 1.5
diff -u -r1.5 vnconfig.8
--- usr.sbin/vnconfig/vnconfig.8 10 Aug 2007 18:28:27 -0000 1.5
+++ usr.sbin/vnconfig/vnconfig.8 7 Jan 2008 18:33:35 -0000
@@ -60,10 +60,13 @@
.Op Fl s Ar option
.Op Fl r Ar option
.Op Fl f Ar config_file
+.Nm
+.Fl l
+.Op Ar special_file Ar ...
.Sh DESCRIPTION
The
.Nm
-command configures and enables vnode pseudo disk devices.
+command configures, enables and lists vnode pseudo disk devices.
The first form of the command will associate the special file
.Ar special_file
with the regular file
@@ -102,6 +105,11 @@
as an alternate config file.
.It Fl g
Fiddle global options.
+.It Fl l Ar special_file...
+List the vn devices and indicate which ones are in use.
+If a
+.Ar special_file
+list is given, only those devices will be described.
.It Fl r Ar flag
Reset
.Ar flag .
Index: usr.sbin/vnconfig/vnconfig.c
===================================================================
RCS file: /home/dcvs/src/usr.sbin/vnconfig/vnconfig.c,v
retrieving revision 1.12
diff -u -r1.12 vnconfig.c
--- usr.sbin/vnconfig/vnconfig.c 19 Jun 2007 19:28:18 -0000 1.12
+++ usr.sbin/vnconfig/vnconfig.c 8 Jan 2008 17:27:47 -0000
@@ -90,12 +90,14 @@
int all = 0;
int verbose = 0;
int global = 0;
+int listopt = 0;
u_long setopt = 0;
u_long resetopt = 0;
char *configfile;
int config(struct vndisk *);
void getoptions(struct vndisk *, char *);
+int getinfo(const char *vname);
char *rawdevice(char *);
void readconfig(int);
static void usage(void);
@@ -113,7 +115,7 @@
char *s;
configfile = _PATH_VNTAB;
- while ((i = getopt(argc, argv, "acdef:gr:s:S:TZL:uv")) != -1)
+ while ((i = getopt(argc, argv, "acdef:glr:s:S:TZL:uv")) != -1)
switch (i) {
/* all -- use config file */
@@ -158,6 +160,10 @@
flags |= VN_RESET;
break;
+ case 'l':
+ listopt = 1;
+ break;
+
/* set options */
case 's':
for (s = strtok(optarg, ","); s; s = strtok(NULL, ",")) {
@@ -204,6 +210,16 @@
if (kldload("vn") < 0 || modfind("vn") < 0)
warnx( "cannot find or load \"vn\" kernel module");
+ if (listopt) {
+ if(argc > optind)
+ while(argc > optind)
+ rv += getinfo( argv[optind++]);
+ else {
+ rv = getinfo( NULL );
+ }
+ exit(rv);
+ }
+
if (flags == 0)
flags = VN_CONFIG;
if (all) {
@@ -240,6 +256,95 @@
return 1;
}
+/*
+ *
+ * GETINFO
+ *
+ * Print vnode disk information to stdout for the device at
+ * path 'vname', or all existing 'vn' devices if none is given.
+ * Any 'vn' devices must exist under /dev in order to be queried.
+ *
+ * Todo: correctly use vm_secsize for swap-backed vn's ..
+ */
+
+int
+getinfo( const char *vname )
+{
+ int i, vd, printlim = 0;
+ char vnpath[PATH_MAX], *tmp;
+
+ struct vn_user vnu;
+ struct stat sb;
+
+ if (vname == NULL) {
+ i = 0;
+ printlim = 1024;
+ }
+ else {
+ tmp = (char *) vname;
+ while (*tmp != NULL) {
+ if(isdigit(*tmp)){
+ i = atoi(tmp);
+ printlim = i + 1;
+ break;
+ }
+ tmp++;
+ }
+ if (tmp == NULL) {
+ printf("unknown vn device: %s", vname);
+ return 1;
+ }
+ }
+
+ snprintf(vnpath, sizeof(vnpath), "/dev/vn%d", i);
+
+ vd = open((char *)vnpath, O_RDONLY);
+ if (vd < 0) {
+ err(1, "open: %s", vnpath);
+ return 1;
+ }
+
+ for (i; i<printlim; i++) {
+
+ bzero((void *) &vnpath, sizeof(vnpath));
+ bzero((void *) &sb, sizeof(struct stat));
+ bzero((void *) &vnu, sizeof(struct vn_user));
+
+ vnu.vnu_unit = i;
+
+ snprintf(vnpath, sizeof(vnpath), "/dev/vn%d", vnu.vnu_unit);
+
+ if(stat(vnpath, &sb) < 0)
+ break;
+ else {
+ if (ioctl(vd, VNIOCGET, &vnu) == -1) {
+ if (errno != ENXIO) {
+ err(1, "ioctl: %s", vname);
+ close(vd);
+ return 1;
+ }
+ }
+
+ fprintf(stdout, "vn%d: ", vnu.vnu_unit);
+
+ if (vnu.vnu_file[0] == 0)
+ fprintf(stdout, "not in use\n");
+ else if ((strcmp(vnu.vnu_file, _VN_USER_SWAP)) == 0)
+ fprintf(stdout,
+ "consuming %d VM pages\n",
+ vnu.vnu_size);
+ else
+ fprintf(stdout,
+ "covering %s on %s, inode %d\n",
+ vnu.vnu_file,
+ devname(vnu.vnu_dev, S_IFBLK),
+ vnu.vnu_ino);
+ }
+ }
+ close(vd);
+ return 0;
+}
+
int
config(struct vndisk *vnp)
{
[
Date Prev][
Date Next]
[
Thread Prev][
Thread Next]
[
Date Index][
Thread Index]