mirror of
https://github.com/opnsense/src.git
synced 2026-05-28 04:12:45 -04:00
Add 'devctl delete' that calls device_delete_child().
'devctl delete' can be used to delete a device that is no longer present.
As an anti-foot-shooting measure, 'delete' will not delete a device
unless it's parent bus says it is no longer present. This can be
overridden by passing the force ('-f') flag.
Note that this command should be used with care. If a device is deleted
that is actually present it can't be resurrected unless the parent bus
device's driver supports rescans.
Differential Revision: https://reviews.freebsd.org/D6019
This commit is contained in:
parent
3d0338a092
commit
88eb5c506d
7 changed files with 113 additions and 4 deletions
|
|
@ -31,6 +31,7 @@
|
|||
.Sh NAME
|
||||
.Nm devctl ,
|
||||
.Nm devctl_attach ,
|
||||
.Nm devctl_delete ,
|
||||
.Nm devctl_detach ,
|
||||
.Nm devctl_disable ,
|
||||
.Nm devctl_enable ,
|
||||
|
|
@ -46,6 +47,8 @@
|
|||
.Ft int
|
||||
.Fn devctl_attach "const char *device"
|
||||
.Ft int
|
||||
.Fn devctl_delete "const char *device" "bool force"
|
||||
.Ft int
|
||||
.Fn devctl_detach "const char *device" "bool force"
|
||||
.Ft int
|
||||
.Fn devctl_disable "const char *device" "bool force_detach"
|
||||
|
|
@ -110,6 +113,15 @@ is true,
|
|||
the current device driver will be detached even if the device is busy.
|
||||
.Pp
|
||||
The
|
||||
.Fn devctl_delete
|
||||
function deletes a device from the device tree.
|
||||
No
|
||||
If
|
||||
.Fa force
|
||||
is true,
|
||||
the device is deleted even if the device is physically present.
|
||||
.Pp
|
||||
The
|
||||
.Fn devctl_disable
|
||||
function disables a device.
|
||||
If the device is currently attached to a device driver,
|
||||
|
|
@ -158,8 +170,8 @@ The
|
|||
function rescans a bus device checking for devices that have been added or
|
||||
removed.
|
||||
.Sh RETURN VALUES
|
||||
.Rv -std devctl_attach devctl_detach devctl_disable devctl_enable \
|
||||
devctl_suspend devctl_rescan devctl_resume devctl_set_driver
|
||||
.Rv -std devctl_attach devctl_delete devctl_detach devctl_disable \
|
||||
devctl_enable devctl_suspend devctl_rescan devctl_resume devctl_set_driver
|
||||
.Sh ERRORS
|
||||
In addition to specific errors noted below,
|
||||
all of the
|
||||
|
|
@ -298,6 +310,19 @@ The device is not attached to a driver.
|
|||
.It Bq Er ENXIO
|
||||
The bus driver does not support rescanning.
|
||||
.El
|
||||
.Pp
|
||||
The
|
||||
.Fn devctl_delete
|
||||
function may fail if:
|
||||
.Bl -tag -width Er
|
||||
.It Bq Er EBUSY
|
||||
The device is physically present and
|
||||
.Fa force
|
||||
is false.
|
||||
.It Bq Er EINVAL
|
||||
.Fa dev
|
||||
is the root device of the device tree.
|
||||
.El
|
||||
.Sh SEE ALSO
|
||||
.Xr devinfo 3 ,
|
||||
.Xr devstat 3 ,
|
||||
|
|
|
|||
|
|
@ -129,3 +129,11 @@ devctl_rescan(const char *device)
|
|||
|
||||
return (devctl_simple_request(DEV_RESCAN, device, 0));
|
||||
}
|
||||
|
||||
int
|
||||
devctl_delete(const char *device, bool force)
|
||||
{
|
||||
|
||||
return (devctl_simple_request(DEV_DELETE, device, force ?
|
||||
DEVF_FORCE_DELETE : 0));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -39,5 +39,6 @@ int devctl_suspend(const char *device);
|
|||
int devctl_resume(const char *device);
|
||||
int devctl_set_driver(const char *device, const char *driver, bool force);
|
||||
int devctl_rescan(const char *device);
|
||||
int devctl_delete(const char *device, bool force);
|
||||
|
||||
#endif /* !__DEVCTL_H__ */
|
||||
|
|
|
|||
|
|
@ -5204,6 +5204,7 @@ devctl2_ioctl(struct cdev *cdev, u_long cmd, caddr_t data, int fflag,
|
|||
case DEV_RESUME:
|
||||
case DEV_SET_DRIVER:
|
||||
case DEV_RESCAN:
|
||||
case DEV_DELETE:
|
||||
error = priv_check(td, PRIV_DRIVER);
|
||||
if (error == 0)
|
||||
error = find_device(req, &dev);
|
||||
|
|
@ -5374,6 +5375,24 @@ devctl2_ioctl(struct cdev *cdev, u_long cmd, caddr_t data, int fflag,
|
|||
}
|
||||
error = BUS_RESCAN(dev);
|
||||
break;
|
||||
case DEV_DELETE: {
|
||||
device_t parent;
|
||||
|
||||
parent = device_get_parent(dev);
|
||||
if (parent == NULL) {
|
||||
error = EINVAL;
|
||||
break;
|
||||
}
|
||||
if (!(req->dr_flags & DEVF_FORCE_DELETE)) {
|
||||
if (bus_child_present(dev) != 0) {
|
||||
error = EBUSY;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
error = device_delete_child(parent, dev);
|
||||
break;
|
||||
}
|
||||
}
|
||||
mtx_unlock(&Giant);
|
||||
return (error);
|
||||
|
|
|
|||
|
|
@ -118,6 +118,7 @@ struct devreq {
|
|||
#define DEV_RESUME _IOW('D', 6, struct devreq)
|
||||
#define DEV_SET_DRIVER _IOW('D', 7, struct devreq)
|
||||
#define DEV_RESCAN _IOW('D', 9, struct devreq)
|
||||
#define DEV_DELETE _IOW('D', 10, struct devreq)
|
||||
|
||||
/* Flags for DEV_DETACH and DEV_DISABLE. */
|
||||
#define DEVF_FORCE_DETACH 0x0000001
|
||||
|
|
@ -125,6 +126,9 @@ struct devreq {
|
|||
/* Flags for DEV_SET_DRIVER. */
|
||||
#define DEVF_SET_DRIVER_DETACH 0x0000001 /* Detach existing driver. */
|
||||
|
||||
/* Flags for DEV_DELETE. */
|
||||
#define DEVF_FORCE_DELETE 0x0000001
|
||||
|
||||
#ifdef _KERNEL
|
||||
|
||||
#include <sys/eventhandler.h>
|
||||
|
|
|
|||
|
|
@ -59,6 +59,10 @@
|
|||
.Nm
|
||||
.Cm rescan
|
||||
.Ar device
|
||||
.Nm
|
||||
.Cm delete
|
||||
.Op Fl f
|
||||
.Ar device
|
||||
.Sh DESCRIPTION
|
||||
The
|
||||
.Nm
|
||||
|
|
@ -132,6 +136,18 @@ the device will not be changed.
|
|||
.It Cm rescan Ar device
|
||||
Rescan a bus device checking for devices that have been added or
|
||||
removed.
|
||||
.It Xo Cm delete
|
||||
.Op Fl
|
||||
.Ar device
|
||||
.Xc
|
||||
Delete the device from the device tree.
|
||||
If the
|
||||
.Fl f
|
||||
flag is specified,
|
||||
the device will be deleted even if it is physically present.
|
||||
This command should be used with care as a device that is deleted but present
|
||||
can no longer be used unless the parent bus device rediscovers the device via
|
||||
a rescan request.
|
||||
.El
|
||||
.Sh SEE ALSO
|
||||
.Xr devctl 3 ,
|
||||
|
|
|
|||
|
|
@ -70,14 +70,16 @@ DEVCTL_TABLE(top, set);
|
|||
static void
|
||||
usage(void)
|
||||
{
|
||||
fprintf(stderr, "%s\n%s\n%s\n%s\n%s\n%s\n%s\n",
|
||||
fprintf(stderr, "%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n",
|
||||
"usage: devctl attach device",
|
||||
" devctl detach [-f] device",
|
||||
" devctl disable [-f] device",
|
||||
" devctl enable device",
|
||||
" devctl suspend device",
|
||||
" devctl resume device",
|
||||
" devctl set driver [-f] device driver");
|
||||
" devctl set driver [-f] device driver",
|
||||
" devctl rescan device",
|
||||
" devctl delete [-f] device");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
|
|
@ -271,6 +273,40 @@ rescan(int ac, char **av)
|
|||
}
|
||||
DEVCTL_COMMAND(top, rescan, rescan);
|
||||
|
||||
static void
|
||||
delete_usage(void)
|
||||
{
|
||||
|
||||
fprintf(stderr, "usage: devctl delete [-f] device\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
static int
|
||||
delete(int ac, char **av)
|
||||
{
|
||||
bool force;
|
||||
int ch;
|
||||
|
||||
force = false;
|
||||
while ((ch = getopt(ac, av, "f")) != -1)
|
||||
switch (ch) {
|
||||
case 'f':
|
||||
force = true;
|
||||
break;
|
||||
default:
|
||||
delete_usage();
|
||||
}
|
||||
ac -= optind;
|
||||
av += optind;
|
||||
|
||||
if (ac != 1)
|
||||
delete_usage();
|
||||
if (devctl_delete(av[0], force) < 0)
|
||||
err(1, "Failed to delete %s", av[0]);
|
||||
return (0);
|
||||
}
|
||||
DEVCTL_COMMAND(top, delete, delete);
|
||||
|
||||
int
|
||||
main(int ac, char *av[])
|
||||
{
|
||||
|
|
|
|||
Loading…
Reference in a new issue