Skip to content
GitLab
Menu
Projects
Groups
Snippets
Loading...
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
Menu
Open sidebar
dadigang
Ventoy
Commits
4527e1db
Commit
4527e1db
authored
Jan 23, 2024
by
longpanda
Browse files
Add support for FreeBSD 14.0
parent
757cacf2
Changes
6
Hide whitespace changes
Inline
Side-by-side
Showing
6 changed files
with
1398 additions
and
0 deletions
+1398
-0
INSTALL/ventoy/ventoy_unix.cpio
INSTALL/ventoy/ventoy_unix.cpio
+0
-0
Unix/ventoy_unix/FreeBSD/geom_ventoy_ko/14.x/32/geom_ventoy.ko.xz
...toy_unix/FreeBSD/geom_ventoy_ko/14.x/32/geom_ventoy.ko.xz
+0
-0
Unix/ventoy_unix/FreeBSD/geom_ventoy_ko/14.x/64/geom_ventoy.ko.xz
...toy_unix/FreeBSD/geom_ventoy_ko/14.x/64/geom_ventoy.ko.xz
+0
-0
Unix/ventoy_unix_src/FreeBSD/geom_ventoy_src/14.x/sys/geom/ventoy/g_ventoy.c
...c/FreeBSD/geom_ventoy_src/14.x/sys/geom/ventoy/g_ventoy.c
+1243
-0
Unix/ventoy_unix_src/FreeBSD/geom_ventoy_src/14.x/sys/geom/ventoy/g_ventoy.h
...c/FreeBSD/geom_ventoy_src/14.x/sys/geom/ventoy/g_ventoy.h
+147
-0
Unix/ventoy_unix_src/FreeBSD/geom_ventoy_src/14.x/sys/modules/geom/geom_ventoy/Makefile
...eom_ventoy_src/14.x/sys/modules/geom/geom_ventoy/Makefile
+8
-0
No files found.
INSTALL/ventoy/ventoy_unix.cpio
View file @
4527e1db
No preview for this file type
Unix/ventoy_unix/FreeBSD/geom_ventoy_ko/14.x/32/geom_ventoy.ko.xz
View file @
4527e1db
No preview for this file type
Unix/ventoy_unix/FreeBSD/geom_ventoy_ko/14.x/64/geom_ventoy.ko.xz
View file @
4527e1db
No preview for this file type
Unix/ventoy_unix_src/FreeBSD/geom_ventoy_src/14.x/sys/geom/ventoy/g_ventoy.c
0 → 100644
View file @
4527e1db
/*-
* SPDX-License-Identifier: BSD-2-Clause-FreeBSD
*
* Copyright (c) 2020 longpanda <admin@ventoy.net>
* Copyright (c) 2004-2005 Pawel Jakub Dawidek <pjd@FreeBSD.org>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#include <sys/cdefs.h>
__FBSDID
(
"$FreeBSD$"
);
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/kernel.h>
#include <sys/module.h>
#include <sys/lock.h>
#include <sys/mutex.h>
#include <sys/sx.h>
#include <sys/bio.h>
#include <sys/sbuf.h>
#include <sys/sysctl.h>
#include <sys/malloc.h>
#include <geom/geom.h>
#include <geom/ventoy/g_ventoy.h>
FEATURE
(
geom_ventoy
,
"GEOM ventoy support"
);
static
MALLOC_DEFINE
(
M_VENTOY
,
"ventoy_data"
,
"GEOM_VENTOY Data"
);
SYSCTL_DECL
(
_kern_geom
);
static
SYSCTL_NODE
(
_kern_geom
,
OID_AUTO
,
ventoy
,
CTLFLAG_RW
|
CTLFLAG_MPSAFE
,
0
,
"GEOM_VENTOY stuff"
);
static
u_int
g_ventoy_debug
=
0
;
SYSCTL_UINT
(
_kern_geom_ventoy
,
OID_AUTO
,
debug
,
CTLFLAG_RWTUN
,
&
g_ventoy_debug
,
0
,
"Debug level"
);
extern
int
resource_string_value
(
const
char
*
name
,
int
unit
,
const
char
*
resname
,
const
char
**
result
);
extern
int
resource_int_value
(
const
char
*
name
,
int
unit
,
const
char
*
resname
,
int
*
result
);
static
int
g_ventoy_destroy
(
struct
g_ventoy_softc
*
sc
,
boolean_t
force
);
static
int
g_ventoy_destroy_geom
(
struct
gctl_req
*
req
,
struct
g_class
*
mp
,
struct
g_geom
*
gp
);
static
g_taste_t
g_ventoy_taste
;
static
g_ctl_req_t
g_ventoy_config
;
static
g_dumpconf_t
g_ventoy_dumpconf
;
static
char
g_ventoy_disk_uuid
[
64
];
static
bool
g_ventoy_tasted
=
false
;
static
off_t
g_ventoy_disk_size
=
0
;
static
off_t
g_disk_map_start
=
0
;
static
off_t
g_disk_map_end
=
0
;
static
int
g_ventoy_remount
=
0
;
struct
g_ventoy_map
g_ventoy_map_data
__attribute__
((
aligned
(
4096
)))
=
{
{
VENTOY_UNIX_SEG_MAGIC0
,
VENTOY_UNIX_SEG_MAGIC1
,
VENTOY_UNIX_SEG_MAGIC2
,
VENTOY_UNIX_SEG_MAGIC3
},
{
0
,
0
,
0
,
0
},
0
,
0
,
{
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
},
{
{
0
,
0
}
},
{
VENTOY_UNIX_SEG_MAGIC0
,
VENTOY_UNIX_SEG_MAGIC1
,
VENTOY_UNIX_SEG_MAGIC2
,
VENTOY_UNIX_SEG_MAGIC3
}
};
struct
g_class
g_ventoy_class
=
{
.
name
=
G_VENTOY_CLASS_NAME
,
.
version
=
G_VERSION
,
.
ctlreq
=
g_ventoy_config
,
.
taste
=
g_ventoy_taste
,
.
destroy_geom
=
g_ventoy_destroy_geom
};
/*
* Greatest Common Divisor.
*/
static
u_int
gcd
(
u_int
a
,
u_int
b
)
{
u_int
c
;
while
(
b
!=
0
)
{
c
=
a
;
a
=
b
;
b
=
(
c
%
b
);
}
return
(
a
);
}
/*
* Least Common Multiple.
*/
static
u_int
lcm
(
u_int
a
,
u_int
b
)
{
return
((
a
*
b
)
/
gcd
(
a
,
b
));
}
/*
* Return the number of valid disks.
*/
static
u_int
g_ventoy_nvalid
(
struct
g_ventoy_softc
*
sc
)
{
u_int
no
;
struct
g_ventoy_disk
*
disk
;
sx_assert
(
&
sc
->
sc_disks_lock
,
SA_LOCKED
);
no
=
0
;
TAILQ_FOREACH
(
disk
,
&
sc
->
sc_disks
,
d_next
)
{
if
(
disk
->
d_consumer
!=
NULL
)
no
++
;
}
return
(
no
);
}
static
void
g_ventoy_remove_disk
(
struct
g_ventoy_disk
*
disk
)
{
struct
g_consumer
*
cp
;
struct
g_ventoy_softc
*
sc
;
g_topology_assert
();
KASSERT
(
disk
->
d_consumer
!=
NULL
,
(
"Non-valid disk in %s."
,
__func__
));
sc
=
disk
->
d_softc
;
cp
=
disk
->
d_consumer
;
if
(
!
disk
->
d_removed
)
{
G_VENTOY_DEBUG
(
0
,
"Disk %s removed from %s."
,
cp
->
provider
->
name
,
sc
->
sc_name
);
disk
->
d_removed
=
1
;
}
if
(
sc
->
sc_provider
!=
NULL
)
{
G_VENTOY_DEBUG
(
0
,
"Device %s deactivated."
,
sc
->
sc_provider
->
name
);
g_wither_provider
(
sc
->
sc_provider
,
ENXIO
);
sc
->
sc_provider
=
NULL
;
}
if
(
cp
->
acr
>
0
||
cp
->
acw
>
0
||
cp
->
ace
>
0
)
return
;
disk
->
d_consumer
=
NULL
;
g_detach
(
cp
);
g_destroy_consumer
(
cp
);
/* If there are no valid disks anymore, remove device. */
if
(
LIST_EMPTY
(
&
sc
->
sc_geom
->
consumer
))
g_ventoy_destroy
(
sc
,
1
);
}
static
void
g_ventoy_orphan
(
struct
g_consumer
*
cp
)
{
struct
g_ventoy_softc
*
sc
;
struct
g_ventoy_disk
*
disk
;
struct
g_geom
*
gp
;
g_topology_assert
();
gp
=
cp
->
geom
;
sc
=
gp
->
softc
;
if
(
sc
==
NULL
)
return
;
disk
=
cp
->
private
;
if
(
disk
==
NULL
)
/* Possible? */
return
;
g_ventoy_remove_disk
(
disk
);
}
static
int
g_ventoy_access
(
struct
g_provider
*
pp
,
int
dr
,
int
dw
,
int
de
)
{
struct
g_consumer
*
cp1
,
*
cp2
,
*
tmp
;
struct
g_ventoy_disk
*
disk
;
struct
g_geom
*
gp
;
struct
g_ventoy_softc
*
sc
;
int
error
;
if
(
dw
>
0
)
/* readonly */
return
(
EPERM
);
g_topology_assert
();
gp
=
pp
->
geom
;
sc
=
gp
->
softc
;
if
(
g_ventoy_remount
)
{
de
=
0
;
}
else
{
/* On first open, grab an extra "exclusive" bit */
if
(
pp
->
acr
==
0
&&
pp
->
acw
==
0
&&
pp
->
ace
==
0
)
de
++
;
/* ... and let go of it on last close */
if
((
pp
->
acr
+
dr
)
==
0
&&
(
pp
->
acw
+
dw
)
==
0
&&
(
pp
->
ace
+
de
)
==
0
)
de
--
;
}
sx_slock
(
&
sc
->
sc_disks_lock
);
LIST_FOREACH_SAFE
(
cp1
,
&
gp
->
consumer
,
consumer
,
tmp
)
{
error
=
g_access
(
cp1
,
dr
,
dw
,
de
);
if
(
error
!=
0
)
goto
fail
;
disk
=
cp1
->
private
;
if
(
cp1
->
acr
==
0
&&
cp1
->
acw
==
0
&&
cp1
->
ace
==
0
&&
disk
->
d_removed
)
{
g_ventoy_remove_disk
(
disk
);
/* May destroy geom. */
}
}
sx_sunlock
(
&
sc
->
sc_disks_lock
);
return
(
0
);
fail:
sx_sunlock
(
&
sc
->
sc_disks_lock
);
LIST_FOREACH
(
cp2
,
&
gp
->
consumer
,
consumer
)
{
if
(
cp1
==
cp2
)
break
;
g_access
(
cp2
,
-
dr
,
-
dw
,
-
de
);
}
return
(
error
);
}
static
void
g_ventoy_candelete
(
struct
bio
*
bp
)
{
struct
g_ventoy_softc
*
sc
;
struct
g_ventoy_disk
*
disk
;
int
val
;
sc
=
bp
->
bio_to
->
geom
->
softc
;
sx_assert
(
&
sc
->
sc_disks_lock
,
SX_LOCKED
);
TAILQ_FOREACH
(
disk
,
&
sc
->
sc_disks
,
d_next
)
{
if
(
!
disk
->
d_removed
&&
disk
->
d_candelete
)
break
;
}
val
=
disk
!=
NULL
;
g_handleattr
(
bp
,
"GEOM::candelete"
,
&
val
,
sizeof
(
val
));
}
static
void
g_ventoy_kernel_dump
(
struct
bio
*
bp
)
{
struct
g_ventoy_softc
*
sc
;
struct
g_ventoy_disk
*
disk
;
struct
bio
*
cbp
;
struct
g_kerneldump
*
gkd
;
sc
=
bp
->
bio_to
->
geom
->
softc
;
gkd
=
(
struct
g_kerneldump
*
)
bp
->
bio_data
;
TAILQ_FOREACH
(
disk
,
&
sc
->
sc_disks
,
d_next
)
{
if
(
disk
->
d_start
<=
gkd
->
offset
&&
disk
->
d_end
>
gkd
->
offset
)
break
;
}
if
(
disk
==
NULL
)
{
g_io_deliver
(
bp
,
EOPNOTSUPP
);
return
;
}
gkd
->
offset
-=
disk
->
d_start
;
if
(
gkd
->
length
>
disk
->
d_end
-
disk
->
d_start
-
gkd
->
offset
)
gkd
->
length
=
disk
->
d_end
-
disk
->
d_start
-
gkd
->
offset
;
cbp
=
g_clone_bio
(
bp
);
if
(
cbp
==
NULL
)
{
g_io_deliver
(
bp
,
ENOMEM
);
return
;
}
cbp
->
bio_done
=
g_std_done
;
g_io_request
(
cbp
,
disk
->
d_consumer
);
G_VENTOY_DEBUG
(
1
,
"Kernel dump will go to %s."
,
disk
->
d_consumer
->
provider
->
name
);
}
static
void
g_ventoy_done
(
struct
bio
*
bp
)
{
struct
g_ventoy_softc
*
sc
;
struct
bio
*
pbp
;
pbp
=
bp
->
bio_parent
;
sc
=
pbp
->
bio_to
->
geom
->
softc
;
mtx_lock
(
&
sc
->
sc_completion_lock
);
if
(
pbp
->
bio_error
==
0
)
pbp
->
bio_error
=
bp
->
bio_error
;
pbp
->
bio_completed
+=
bp
->
bio_completed
;
pbp
->
bio_inbed
++
;
if
(
pbp
->
bio_children
==
pbp
->
bio_inbed
)
{
mtx_unlock
(
&
sc
->
sc_completion_lock
);
g_io_deliver
(
pbp
,
pbp
->
bio_error
);
}
else
mtx_unlock
(
&
sc
->
sc_completion_lock
);
g_destroy_bio
(
bp
);
}
static
void
g_ventoy_flush
(
struct
g_ventoy_softc
*
sc
,
struct
bio
*
bp
)
{
struct
bio_queue_head
queue
;
struct
g_consumer
*
cp
;
struct
bio
*
cbp
;
struct
g_ventoy_disk
*
disk
;
sx_assert
(
&
sc
->
sc_disks_lock
,
SX_LOCKED
);
bioq_init
(
&
queue
);
TAILQ_FOREACH
(
disk
,
&
sc
->
sc_disks
,
d_next
)
{
cbp
=
g_clone_bio
(
bp
);
if
(
cbp
==
NULL
)
{
while
((
cbp
=
bioq_takefirst
(
&
queue
))
!=
NULL
)
g_destroy_bio
(
cbp
);
if
(
bp
->
bio_error
==
0
)
bp
->
bio_error
=
ENOMEM
;
g_io_deliver
(
bp
,
bp
->
bio_error
);
return
;
}
bioq_insert_tail
(
&
queue
,
cbp
);
cbp
->
bio_done
=
g_ventoy_done
;
cbp
->
bio_caller1
=
disk
->
d_consumer
;
cbp
->
bio_to
=
disk
->
d_consumer
->
provider
;
}
while
((
cbp
=
bioq_takefirst
(
&
queue
))
!=
NULL
)
{
G_VENTOY_LOGREQ
(
cbp
,
"Sending request."
);
cp
=
cbp
->
bio_caller1
;
cbp
->
bio_caller1
=
NULL
;
g_io_request
(
cbp
,
cp
);
}
}
static
void
g_ventoy_start
(
struct
bio
*
bp
)
{
struct
bio_queue_head
queue
;
struct
g_ventoy_softc
*
sc
;
struct
g_ventoy_disk
*
disk
;
struct
g_provider
*
pp
;
off_t
offset
,
end
,
length
,
off
,
len
;
struct
bio
*
cbp
;
char
*
addr
;
pp
=
bp
->
bio_to
;
sc
=
pp
->
geom
->
softc
;
/*
* If sc == NULL, provider's error should be set and g_ventoy_start()
* should not be called at all.
*/
KASSERT
(
sc
!=
NULL
,
(
"Provider's error should be set (error=%d)(device=%s)."
,
bp
->
bio_to
->
error
,
bp
->
bio_to
->
name
));
G_VENTOY_LOGREQ
(
bp
,
"Request received."
);
sx_slock
(
&
sc
->
sc_disks_lock
);
switch
(
bp
->
bio_cmd
)
{
case
BIO_READ
:
case
BIO_WRITE
:
case
BIO_DELETE
:
break
;
case
BIO_SPEEDUP
:
case
BIO_FLUSH
:
g_ventoy_flush
(
sc
,
bp
);
goto
end
;
case
BIO_GETATTR
:
if
(
strcmp
(
"GEOM::kerneldump"
,
bp
->
bio_attribute
)
==
0
)
{
g_ventoy_kernel_dump
(
bp
);
goto
end
;
}
else
if
(
strcmp
(
"GEOM::candelete"
,
bp
->
bio_attribute
)
==
0
)
{
g_ventoy_candelete
(
bp
);
goto
end
;
}
/* To which provider it should be delivered? */
/* FALLTHROUGH */
default:
g_io_deliver
(
bp
,
EOPNOTSUPP
);
goto
end
;
}
offset
=
bp
->
bio_offset
;
length
=
bp
->
bio_length
;
if
((
bp
->
bio_flags
&
BIO_UNMAPPED
)
!=
0
)
addr
=
NULL
;
else
addr
=
bp
->
bio_data
;
end
=
offset
+
length
;
bioq_init
(
&
queue
);
TAILQ_FOREACH
(
disk
,
&
sc
->
sc_disks
,
d_next
)
{
if
(
disk
->
d_end
<=
offset
)
continue
;
if
(
disk
->
d_start
>=
end
)
break
;
off
=
offset
-
disk
->
d_start
;
len
=
MIN
(
length
,
disk
->
d_end
-
offset
);
length
-=
len
;
offset
+=
len
;
cbp
=
g_clone_bio
(
bp
);
if
(
cbp
==
NULL
)
{
while
((
cbp
=
bioq_takefirst
(
&
queue
))
!=
NULL
)
g_destroy_bio
(
cbp
);
if
(
bp
->
bio_error
==
0
)
bp
->
bio_error
=
ENOMEM
;
g_io_deliver
(
bp
,
bp
->
bio_error
);
goto
end
;
}
bioq_insert_tail
(
&
queue
,
cbp
);
/*
* Fill in the component buf structure.
*/
if
(
len
==
bp
->
bio_length
)
cbp
->
bio_done
=
g_std_done
;
else
cbp
->
bio_done
=
g_ventoy_done
;
cbp
->
bio_offset
=
off
+
disk
->
d_map_start
;
cbp
->
bio_length
=
len
;
if
((
bp
->
bio_flags
&
BIO_UNMAPPED
)
!=
0
)
{
cbp
->
bio_ma_offset
+=
(
uintptr_t
)
addr
;
cbp
->
bio_ma
+=
cbp
->
bio_ma_offset
/
PAGE_SIZE
;
cbp
->
bio_ma_offset
%=
PAGE_SIZE
;
cbp
->
bio_ma_n
=
round_page
(
cbp
->
bio_ma_offset
+
cbp
->
bio_length
)
/
PAGE_SIZE
;
}
else
cbp
->
bio_data
=
addr
;
addr
+=
len
;
cbp
->
bio_to
=
disk
->
d_consumer
->
provider
;
cbp
->
bio_caller1
=
disk
;
if
(
length
==
0
)
break
;
}
KASSERT
(
length
==
0
,
(
"Length is still greater than 0 (class=%s, name=%s)."
,
bp
->
bio_to
->
geom
->
class
->
name
,
bp
->
bio_to
->
geom
->
name
));
while
((
cbp
=
bioq_takefirst
(
&
queue
))
!=
NULL
)
{
G_VENTOY_LOGREQ
(
cbp
,
"Sending request."
);
disk
=
cbp
->
bio_caller1
;
cbp
->
bio_caller1
=
NULL
;
g_io_request
(
cbp
,
disk
->
d_consumer
);
}
end:
sx_sunlock
(
&
sc
->
sc_disks_lock
);
}
static
void
g_ventoy_check_and_run
(
struct
g_ventoy_softc
*
sc
)
{
struct
g_ventoy_disk
*
disk
;
struct
g_provider
*
dp
,
*
pp
;
u_int
sectorsize
=
0
;
off_t
start
;
int
error
;
g_topology_assert
();
if
(
g_ventoy_nvalid
(
sc
)
!=
sc
->
sc_ndisks
)
return
;
pp
=
g_new_providerf
(
sc
->
sc_geom
,
"ventoy/%s"
,
sc
->
sc_name
);
pp
->
flags
|=
G_PF_DIRECT_SEND
|
G_PF_DIRECT_RECEIVE
|
G_PF_ACCEPT_UNMAPPED
;
start
=
0
;
TAILQ_FOREACH
(
disk
,
&
sc
->
sc_disks
,
d_next
)
{
dp
=
disk
->
d_consumer
->
provider
;
disk
->
d_start
=
start
;
disk
->
d_end
=
disk
->
d_start
+
(
disk
->
d_map_end
-
disk
->
d_map_start
);
if
(
sc
->
sc_type
==
G_VENTOY_TYPE_AUTOMATIC
)
disk
->
d_end
-=
dp
->
sectorsize
;
start
=
disk
->
d_end
;
error
=
g_access
(
disk
->
d_consumer
,
1
,
0
,
0
);
if
(
error
==
0
)
{
error
=
g_getattr
(
"GEOM::candelete"
,
disk
->
d_consumer
,
&
disk
->
d_candelete
);
if
(
error
!=
0
)
disk
->
d_candelete
=
0
;
(
void
)
g_access
(
disk
->
d_consumer
,
-
1
,
0
,
0
);
}
else
G_VENTOY_DEBUG
(
1
,
"Failed to access disk %s, error %d."
,
dp
->
name
,
error
);
if
(
disk
==
TAILQ_FIRST
(
&
sc
->
sc_disks
))
sectorsize
=
dp
->
sectorsize
;
else
sectorsize
=
lcm
(
sectorsize
,
dp
->
sectorsize
);
/* A provider underneath us doesn't support unmapped */
if
((
dp
->
flags
&
G_PF_ACCEPT_UNMAPPED
)
==
0
)
{
G_VENTOY_DEBUG
(
1
,
"Cancelling unmapped "
"because of %s."
,
dp
->
name
);
pp
->
flags
&=
~
G_PF_ACCEPT_UNMAPPED
;
}
}
pp
->
sectorsize
=
sectorsize
;
/* We have sc->sc_disks[sc->sc_ndisks - 1].d_end in 'start'. */
pp
->
mediasize
=
start
;
dp
=
TAILQ_FIRST
(
&
sc
->
sc_disks
)
->
d_consumer
->
provider
;
pp
->
stripesize
=
dp
->
stripesize
;
pp
->
stripeoffset
=
dp
->
stripeoffset
;
sc
->
sc_provider
=
pp
;
g_error_provider
(
pp
,
0
);
G_VENTOY_DEBUG
(
0
,
"Device %s activated."
,
sc
->
sc_provider
->
name
);
}
static
int
g_ventoy_read_metadata
(
struct
g_consumer
*
cp
,
struct
g_ventoy_metadata
*
md
)
{
struct
g_provider
*
pp
;
u_char
*
buf
;
int
error
;
g_topology_assert
();
error
=
g_access
(
cp
,
1
,
0
,
0
);
if
(
error
!=
0
)
return
(
error
);
pp
=
cp
->
provider
;
g_topology_unlock
();
buf
=
g_read_data
(
cp
,
pp
->
mediasize
-
pp
->
sectorsize
,
pp
->
sectorsize
,
&
error
);
g_topology_lock
();
g_access
(
cp
,
-
1
,
0
,
0
);
if
(
buf
==
NULL
)
return
(
error
);
/* Decode metadata. */
ventoy_metadata_decode
(
buf
,
md
);
g_free
(
buf
);
return
(
0
);
}
/*
* Add disk to given device.
*/
static
int
g_ventoy_add_disk
(
struct
g_ventoy_softc
*
sc
,
struct
g_provider
*
pp
,
u_int
no
)
{
struct
g_ventoy_disk
*
disk
;
struct
g_consumer
*
cp
,
*
fcp
;
struct
g_geom
*
gp
;
int
error
;
g_topology_assert
();
sx_slock
(
&
sc
->
sc_disks_lock
);
/* Metadata corrupted? */
if
(
no
>=
sc
->
sc_ndisks
)
{
sx_sunlock
(
&
sc
->
sc_disks_lock
);
return
(
EINVAL
);
}
for
(
disk
=
TAILQ_FIRST
(
&
sc
->
sc_disks
);
no
>
0
;
no
--
)
{
disk
=
TAILQ_NEXT
(
disk
,
d_next
);
}
/* Check if disk is not already attached. */
if
(
disk
->
d_consumer
!=
NULL
)
{
sx_sunlock
(
&
sc
->
sc_disks_lock
);
return
(
EEXIST
);
}
gp
=
sc
->
sc_geom
;
fcp
=
LIST_FIRST
(
&
gp
->
consumer
);
cp
=
g_new_consumer
(
gp
);
cp
->
flags
|=
G_CF_DIRECT_SEND
|
G_CF_DIRECT_RECEIVE
;
error
=
g_attach
(
cp
,
pp
);
if
(
error
!=
0
)
{
sx_sunlock
(
&
sc
->
sc_disks_lock
);
g_destroy_consumer
(
cp
);
return
(
error
);
}
if
(
fcp
!=
NULL
&&
(
fcp
->
acr
>
0
||
fcp
->
acw
>
0
||
fcp
->
ace
>
0
))
{
error
=
g_access
(
cp
,
fcp
->
acr
,
fcp
->
acw
,
fcp
->
ace
);
if
(
error
!=
0
)
{
sx_sunlock
(
&
sc
->
sc_disks_lock
);
g_detach
(
cp
);
g_destroy_consumer
(
cp
);
return
(
error
);
}
}
if
(
sc
->
sc_type
==
G_VENTOY_TYPE_AUTOMATIC
)
{
struct
g_ventoy_metadata
md
;
// temporarily give up the lock to avoid lock order violation
// due to topology unlock in g_concat_read_metadata
sx_sunlock
(
&
sc
->
sc_disks_lock
);
/* Re-read metadata. */
error
=
g_ventoy_read_metadata
(
cp
,
&
md
);
sx_slock
(
&
sc
->
sc_disks_lock
);
if
(
error
!=
0
)
goto
fail
;
if
(
strcmp
(
md
.
md_magic
,
G_VENTOY_MAGIC
)
!=
0
||
strcmp
(
md
.
md_name
,
sc
->
sc_name
)
!=
0
||
md
.
md_id
!=
sc
->
sc_id
)
{
G_VENTOY_DEBUG
(
0
,
"Metadata on %s changed."
,
pp
->
name
);
goto
fail
;
}
disk
->
d_hardcoded
=
md
.
md_provider
[
0
]
!=
'\0'
;
}
else
{
disk
->
d_hardcoded
=
false
;
}
cp
->
private
=
disk
;
disk
->
d_consumer
=
cp
;
disk
->
d_softc
=
sc
;
disk
->
d_start
=
0
;
/* not yet */
disk
->
d_end
=
0
;
/* not yet */
disk
->
d_removed
=
0
;
disk
->
d_map_start
=
g_disk_map_start
;
disk
->
d_map_end
=
g_disk_map_end
;
G_VENTOY_DEBUG
(
0
,
"Disk %s attached to %s."
,
pp
->
name
,
sc
->
sc_name
);
g_ventoy_check_and_run
(
sc
);
sx_sunlock
(
&
sc
->
sc_disks_lock
);
// need lock for check_and_run
return
(
0
);
fail:
sx_sunlock
(
&
sc
->
sc_disks_lock
);
// need lock for check_and_run
if
(
fcp
!=
NULL
&&
(
fcp
->
acr
>
0
||
fcp
->
acw
>
0
||
fcp
->
ace
>
0
))
g_access
(
cp
,
-
fcp
->
acr
,
-
fcp
->
acw
,
-
fcp
->
ace
);
g_detach
(
cp
);
g_destroy_consumer
(
cp
);
return
(
error
);
}
static
struct
g_geom
*
g_ventoy_create
(
struct
g_class
*
mp
,
const
struct
g_ventoy_metadata
*
md
,
u_int
type
)
{
struct
g_ventoy_softc
*
sc
;
struct
g_ventoy_disk
*
disk
;
struct
g_geom
*
gp
;
u_int
no
;
G_VENTOY_DEBUG
(
1
,
"Creating device %s (id=%u)."
,
md
->
md_name
,
md
->
md_id
);
/* One disks is minimum. */
if
(
md
->
md_all
<
1
)
return
(
NULL
);
/* Check for duplicate unit */
LIST_FOREACH
(
gp
,
&
mp
->
geom
,
geom
)
{
sc
=
gp
->
softc
;
if
(
sc
!=
NULL
&&
strcmp
(
sc
->
sc_name
,
md
->
md_name
)
==
0
)
{
G_VENTOY_DEBUG
(
0
,
"Device %s already configured."
,
gp
->
name
);
return
(
NULL
);
}
}
gp
=
g_new_geomf
(
mp
,
"%s"
,
md
->
md_name
);
sc
=
malloc
(
sizeof
(
*
sc
),
M_VENTOY
,
M_WAITOK
|
M_ZERO
);
gp
->
start
=
g_ventoy_start
;
gp
->
spoiled
=
g_ventoy_orphan
;
gp
->
orphan
=
g_ventoy_orphan
;
gp
->
access
=
g_ventoy_access
;
gp
->
dumpconf
=
g_ventoy_dumpconf
;
sc
->
sc_id
=
md
->
md_id
;
sc
->
sc_ndisks
=
md
->
md_all
;
TAILQ_INIT
(
&
sc
->
sc_disks
);
for
(
no
=
0
;
no
<
sc
->
sc_ndisks
;
no
++
)
{
disk
=
malloc
(
sizeof
(
*
disk
),
M_VENTOY
,
M_WAITOK
|
M_ZERO
);
TAILQ_INSERT_TAIL
(
&
sc
->
sc_disks
,
disk
,
d_next
);
}
sc
->
sc_type
=
type
;
mtx_init
(
&
sc
->
sc_completion_lock
,
"gventoy lock"
,
NULL
,
MTX_DEF
);
sx_init
(
&
sc
->
sc_disks_lock
,
"gventoy append lock"
);
gp
->
softc
=
sc
;
sc
->
sc_geom
=
gp
;
sc
->
sc_provider
=
NULL
;
G_VENTOY_DEBUG
(
0
,
"Device %s created (id=%u)."
,
sc
->
sc_name
,
sc
->
sc_id
);
return
(
gp
);
}
static
int
g_ventoy_destroy
(
struct
g_ventoy_softc
*
sc
,
boolean_t
force
)
{
struct
g_provider
*
pp
;
struct
g_consumer
*
cp
,
*
cp1
;
struct
g_geom
*
gp
;
struct
g_ventoy_disk
*
disk
;
g_topology_assert
();
if
(
sc
==
NULL
)
return
(
ENXIO
);
pp
=
sc
->
sc_provider
;
if
(
pp
!=
NULL
&&
(
pp
->
acr
!=
0
||
pp
->
acw
!=
0
||
pp
->
ace
!=
0
))
{
if
(
force
)
{
G_VENTOY_DEBUG
(
0
,
"Device %s is still open, so it "
"can't be definitely removed."
,
pp
->
name
);
}
else
{
G_VENTOY_DEBUG
(
1
,
"Device %s is still open (r%dw%de%d)."
,
pp
->
name
,
pp
->
acr
,
pp
->
acw
,
pp
->
ace
);
return
(
EBUSY
);
}
}
gp
=
sc
->
sc_geom
;
LIST_FOREACH_SAFE
(
cp
,
&
gp
->
consumer
,
consumer
,
cp1
)
{
g_ventoy_remove_disk
(
cp
->
private
);
if
(
cp1
==
NULL
)
return
(
0
);
/* Recursion happened. */
}
if
(
!
LIST_EMPTY
(
&
gp
->
consumer
))
return
(
EINPROGRESS
);
gp
->
softc
=
NULL
;
KASSERT
(
sc
->
sc_provider
==
NULL
,
(
"Provider still exists? (device=%s)"
,
gp
->
name
));
while
((
disk
=
TAILQ_FIRST
(
&
sc
->
sc_disks
))
!=
NULL
)
{
TAILQ_REMOVE
(
&
sc
->
sc_disks
,
disk
,
d_next
);
free
(
disk
,
M_VENTOY
);
}
mtx_destroy
(
&
sc
->
sc_completion_lock
);
sx_destroy
(
&
sc
->
sc_disks_lock
);
free
(
sc
,
M_VENTOY
);
G_VENTOY_DEBUG
(
0
,
"Device %s destroyed."
,
gp
->
name
);
g_wither_geom
(
gp
,
ENXIO
);
return
(
0
);
}
static
int
g_ventoy_destroy_geom
(
struct
gctl_req
*
req
__unused
,
struct
g_class
*
mp
__unused
,
struct
g_geom
*
gp
)
{
struct
g_ventoy_softc
*
sc
;
sc
=
gp
->
softc
;
return
(
g_ventoy_destroy
(
sc
,
0
));
}
static
bool
g_vtoy_check_disk
(
struct
g_class
*
mp
,
struct
g_provider
*
pp
)
{
int
i
;
int
vlnk
=
0
;
bool
ret
=
true
;
uint8_t
*
buf
;
char
uuid
[
64
];
const
char
*
value
;
struct
g_consumer
*
cp
;
struct
g_geom
*
gp
;
uint8_t
mbrdata
[]
=
{
0xEB
,
0x63
,
0x90
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x56
,
0x54
,
0x00
,
0x47
,
0x65
,
0x00
,
0x48
,
0x44
,
0x00
,
0x52
,
0x64
,
0x00
,
0x20
,
0x45
,
0x72
,
0x0D
,
};
if
(
g_ventoy_disk_size
==
0
)
{
if
(
VENTOY_MAP_VALID
(
g_ventoy_map_data
.
magic2
))
{
G_DEBUG
(
"ventoy map data is valid. [OK]
\n
"
);
for
(
i
=
0
;
i
<
16
;
i
++
)
{
sprintf
(
uuid
+
i
*
2
,
"%02x"
,
g_ventoy_map_data
.
diskuuid
[
i
]);
}
snprintf
(
g_ventoy_disk_uuid
,
sizeof
(
g_ventoy_disk_uuid
),
"%s"
,
uuid
);
g_ventoy_disk_size
=
g_ventoy_map_data
.
disksize
;
G_DEBUG
(
"ventoy.disksize: %llu
\n
"
,
(
unsigned
long
long
)
g_ventoy_disk_size
);
G_DEBUG
(
"ventoy.diskuuid: <%s>
\n
"
,
g_ventoy_disk_uuid
);
}
else
{
G_DEBUG
(
"ventoy map data is invalid, get from resource
\n
"
);
if
(
resource_string_value
(
"ventoy"
,
0
,
"disksize"
,
&
value
)
==
0
)
{
G_DEBUG
(
"ventoy.disksize: %s
\n
"
,
value
);
g_ventoy_disk_size
=
strtouq
(
value
,
NULL
,
0
);
}
if
(
resource_string_value
(
"ventoy"
,
0
,
"diskuuid"
,
&
value
)
==
0
)
{
snprintf
(
g_ventoy_disk_uuid
,
sizeof
(
g_ventoy_disk_uuid
),
"%s"
,
value
);
G_DEBUG
(
"ventoy.diskuuid: <%s>
\n
"
,
value
);
}
}
}
if
(
g_ventoy_disk_size
!=
pp
->
mediasize
)
{
return
false
;
}
if
(
strncmp
(
pp
->
name
,
"cd"
,
2
)
==
0
||
strchr
(
pp
->
name
,
'/'
))
{
return
false
;
}
/* read UUID from disk */
gp
=
g_new_geomf
(
mp
,
"ventoy:taste"
);
gp
->
start
=
NULL
;
gp
->
access
=
g_ventoy_access
;
gp
->
orphan
=
g_ventoy_orphan
;
cp
=
g_new_consumer
(
gp
);
cp
->
flags
|=
G_CF_DIRECT_SEND
|
G_CF_DIRECT_RECEIVE
;
g_attach
(
cp
,
pp
);
g_access
(
cp
,
1
,
0
,
0
);
g_topology_unlock
();
buf
=
g_read_data
(
cp
,
0
,
pp
->
sectorsize
,
NULL
);
g_topology_lock
();
g_access
(
cp
,
-
1
,
0
,
0
);
g_detach
(
cp
);
g_destroy_consumer
(
cp
);
g_destroy_geom
(
gp
);
gp
=
NULL
;
if
(
!
buf
)
{
return
false
;
}
for
(
i
=
0
;
i
<
16
;
i
++
)
{
sprintf
(
uuid
+
i
*
2
,
"%02x"
,
buf
[
0x180
+
i
]);
}
if
(
strncmp
(
g_ventoy_disk_uuid
,
uuid
,
32
))
{
ret
=
false
;
}
if
(
resource_int_value
(
"ventoy"
,
0
,
"vlnk"
,
&
vlnk
)
||
(
vlnk
!=
1
))
{
if
(
memcmp
(
mbrdata
,
buf
,
0x30
)
||
memcmp
(
mbrdata
+
0x30
,
buf
+
0x190
,
16
))
{
ret
=
false
;
}
}
g_free
(
buf
);
if
(
ret
)
{
G_DEBUG
(
"ventoy disk check OK
\n
"
);
}
return
ret
;
}
static
struct
g_geom
*
g_ventoy_taste
(
struct
g_class
*
mp
,
struct
g_provider
*
pp
,
int
flags
__unused
)
{
int
i
;
int
error
;
int
disknum
;
int
remount
=
0
;
char
*
endpos
;
const
char
*
value
;
const
char
*
alias
=
NULL
;
struct
g_geom
*
gp
;
struct
g_ventoy_metadata
md
;
struct
g_ventoy_softc
*
sc
;
if
(
g_ventoy_tasted
)
{
return
NULL
;
}
G_DEBUG
(
"%s(%s, %s)
\n
"
,
__func__
,
mp
->
name
,
pp
->
name
);
g_topology_assert
();
/* Skip providers that are already open for writing. */
if
(
pp
->
acw
>
0
)
return
(
NULL
);
if
(
!
g_vtoy_check_disk
(
mp
,
pp
))
{
return
NULL
;
}
g_ventoy_tasted
=
true
;
G_DEBUG
(
"###### ventoy disk <%s> ######
\n
"
,
pp
->
name
);
/* hint.ventoy.0.remount=1 */
if
(
resource_int_value
(
"ventoy"
,
0
,
"remount"
,
&
remount
)
==
0
&&
remount
==
1
)
{
g_ventoy_remount
=
1
;
G_DEBUG
(
"###### ventoy remount enabled ######
\n
"
);
}
/* hint.ventoy.0.alias=xxx */
if
(
resource_string_value
(
"ventoy"
,
0
,
"alias"
,
&
alias
)
==
0
)
{
G_DEBUG
(
"###### ventoy alias <%s> ######
\n
"
,
alias
);
}
else
{
alias
=
NULL
;
}
if
(
VENTOY_MAP_VALID
(
g_ventoy_map_data
.
magic2
))
{
disknum
=
(
int
)
g_ventoy_map_data
.
segnum
;
G_DEBUG
(
"segnum from map data is:<%d>
\n
"
,
disknum
);
}
else
{
resource_int_value
(
"ventoy"
,
0
,
"segnum"
,
&
disknum
);
G_DEBUG
(
"segnum from resource is:<%d>
\n
"
,
disknum
);
}
strlcpy
(
md
.
md_magic
,
G_VENTOY_MAGIC
,
sizeof
(
md
.
md_magic
));
md
.
md_version
=
G_VENTOY_VERSION
;
strlcpy
(
md
.
md_name
,
"IMAGE"
,
sizeof
(
md
.
md_name
));
md
.
md_id
=
arc4random
();
md
.
md_no
=
0
;
md
.
md_all
=
(
uint16_t
)
disknum
;
bzero
(
md
.
md_provider
,
sizeof
(
md
.
md_provider
));
/* This field is not important here. */
md
.
md_provsize
=
0
;
gp
=
g_ventoy_create
(
mp
,
&
md
,
G_VENTOY_TYPE_MANUAL
);
if
(
gp
==
NULL
)
{
G_VENTOY_DEBUG
(
0
,
"Cannot create device %s."
,
md
.
md_name
);
return
(
NULL
);
}
sc
=
gp
->
softc
;
for
(
i
=
0
;
i
<
disknum
;
i
++
)
{
if
(
VENTOY_MAP_VALID
(
g_ventoy_map_data
.
magic2
))
{
G_DEBUG
(
"[map] ventoy segment%d: 0x%llx@0x%llx
\n
"
,
i
,
(
long
long
)
g_ventoy_map_data
.
seglist
[
i
].
seg_start_bytes
,
(
long
long
)
g_ventoy_map_data
.
seglist
[
i
].
seg_end_bytes
);
g_disk_map_start
=
(
off_t
)
g_ventoy_map_data
.
seglist
[
i
].
seg_start_bytes
;
g_disk_map_end
=
(
off_t
)
g_ventoy_map_data
.
seglist
[
i
].
seg_end_bytes
;
}
else
{
if
(
resource_string_value
(
"ventoy"
,
i
,
"seg"
,
&
value
)
==
0
)
{
g_disk_map_start
=
strtouq
(
value
,
&
endpos
,
0
);
g_disk_map_end
=
strtouq
(
endpos
+
1
,
NULL
,
0
);
}
else
{
printf
(
"Failed to parse ventoy seg %d
\n
"
,
i
);
continue
;
}
G_DEBUG
(
"[resource] ventoy segment%d: %s
\n
"
,
i
,
value
);
}
G_VENTOY_DEBUG
(
1
,
"Adding disk %s to %s."
,
pp
->
name
,
gp
->
name
);
error
=
g_ventoy_add_disk
(
sc
,
pp
,
i
);
if
(
error
!=
0
)
{
G_VENTOY_DEBUG
(
0
,
"Cannot add disk %s to %s (error=%d)."
,
pp
->
name
,
gp
->
name
,
error
);
g_ventoy_destroy
(
sc
,
1
);
return
(
NULL
);
}
g_disk_map_start
=
0
;
g_disk_map_end
=
0
;
}
if
(
alias
&&
sc
&&
sc
->
sc_provider
)
{
g_provider_add_alias
(
sc
->
sc_provider
,
"%s"
,
alias
);
}
return
(
gp
);
}
static
void
g_ventoy_ctl_create
(
struct
gctl_req
*
req
,
struct
g_class
*
mp
)
{
u_int
attached
,
no
;
struct
g_ventoy_metadata
md
;
struct
g_provider
*
pp
;
struct
g_ventoy_softc
*
sc
;
struct
g_geom
*
gp
;
struct
sbuf
*
sb
;
const
char
*
name
;
char
param
[
16
];
int
*
nargs
;
g_topology_assert
();
nargs
=
gctl_get_paraml
(
req
,
"nargs"
,
sizeof
(
*
nargs
));
if
(
nargs
==
NULL
)
{
gctl_error
(
req
,
"No '%s' argument."
,
"nargs"
);
return
;
}
if
(
*
nargs
<
2
)
{
gctl_error
(
req
,
"Too few arguments."
);
return
;
}
bzero
(
&
md
,
sizeof
(
md
));
strlcpy
(
md
.
md_magic
,
G_VENTOY_MAGIC
,
sizeof
(
md
.
md_magic
));
md
.
md_version
=
G_VENTOY_VERSION
;
name
=
gctl_get_asciiparam
(
req
,
"arg0"
);
if
(
name
==
NULL
)
{
gctl_error
(
req
,
"No 'arg%u' argument."
,
0
);
return
;
}
strlcpy
(
md
.
md_name
,
name
,
sizeof
(
md
.
md_name
));
md
.
md_id
=
arc4random
();
md
.
md_no
=
0
;
md
.
md_all
=
*
nargs
-
1
;
/* This field is not important here. */
md
.
md_provsize
=
0
;
/* Check all providers are valid */
for
(
no
=
1
;
no
<
*
nargs
;
no
++
)
{
snprintf
(
param
,
sizeof
(
param
),
"arg%u"
,
no
);
pp
=
gctl_get_provider
(
req
,
param
);
if
(
pp
==
NULL
)
return
;
}
gp
=
g_ventoy_create
(
mp
,
&
md
,
G_VENTOY_TYPE_MANUAL
);
if
(
gp
==
NULL
)
{
gctl_error
(
req
,
"Can't configure %s."
,
md
.
md_name
);
return
;
}
sc
=
gp
->
softc
;
sb
=
sbuf_new_auto
();
sbuf_printf
(
sb
,
"Can't attach disk(s) to %s:"
,
gp
->
name
);
for
(
attached
=
0
,
no
=
1
;
no
<
*
nargs
;
no
++
)
{
snprintf
(
param
,
sizeof
(
param
),
"arg%u"
,
no
);
pp
=
gctl_get_provider
(
req
,
param
);
if
(
pp
==
NULL
)
{
name
=
gctl_get_asciiparam
(
req
,
param
);
MPASS
(
name
!=
NULL
);
sbuf_printf
(
sb
,
" %s"
,
name
);
continue
;
}
if
(
g_ventoy_add_disk
(
sc
,
pp
,
no
-
1
)
!=
0
)
{
G_VENTOY_DEBUG
(
1
,
"Disk %u (%s) not attached to %s."
,
no
,
pp
->
name
,
gp
->
name
);
sbuf_printf
(
sb
,
" %s"
,
pp
->
name
);
continue
;
}
attached
++
;
}
sbuf_finish
(
sb
);
if
(
md
.
md_all
!=
attached
)
{
g_ventoy_destroy
(
gp
->
softc
,
1
);
gctl_error
(
req
,
"%s"
,
sbuf_data
(
sb
));
}
sbuf_delete
(
sb
);
}
static
struct
g_ventoy_softc
*
g_ventoy_find_device
(
struct
g_class
*
mp
,
const
char
*
name
)
{
struct
g_ventoy_softc
*
sc
;
struct
g_geom
*
gp
;
if
(
strncmp
(
name
,
_PATH_DEV
,
strlen
(
_PATH_DEV
))
==
0
)
name
+=
strlen
(
_PATH_DEV
);
LIST_FOREACH
(
gp
,
&
mp
->
geom
,
geom
)
{
sc
=
gp
->
softc
;
if
(
sc
==
NULL
)
continue
;
if
(
strcmp
(
sc
->
sc_name
,
name
)
==
0
)
return
(
sc
);
}
return
(
NULL
);
}
static
void
g_ventoy_ctl_destroy
(
struct
gctl_req
*
req
,
struct
g_class
*
mp
)
{
struct
g_ventoy_softc
*
sc
;
int
*
force
,
*
nargs
,
error
;
const
char
*
name
;
char
param
[
16
];
u_int
i
;
g_topology_assert
();
nargs
=
gctl_get_paraml
(
req
,
"nargs"
,
sizeof
(
*
nargs
));
if
(
nargs
==
NULL
)
{
gctl_error
(
req
,
"No '%s' argument."
,
"nargs"
);
return
;
}
if
(
*
nargs
<=
0
)
{
gctl_error
(
req
,
"Missing device(s)."
);
return
;
}
force
=
gctl_get_paraml
(
req
,
"force"
,
sizeof
(
*
force
));
if
(
force
==
NULL
)
{
gctl_error
(
req
,
"No '%s' argument."
,
"force"
);
return
;
}
for
(
i
=
0
;
i
<
(
u_int
)
*
nargs
;
i
++
)
{
snprintf
(
param
,
sizeof
(
param
),
"arg%u"
,
i
);
name
=
gctl_get_asciiparam
(
req
,
param
);
if
(
name
==
NULL
)
{
gctl_error
(
req
,
"No 'arg%u' argument."
,
i
);
return
;
}
sc
=
g_ventoy_find_device
(
mp
,
name
);
if
(
sc
==
NULL
)
{
gctl_error
(
req
,
"No such device: %s."
,
name
);
return
;
}
error
=
g_ventoy_destroy
(
sc
,
*
force
);
if
(
error
!=
0
)
{
gctl_error
(
req
,
"Cannot destroy device %s (error=%d)."
,
sc
->
sc_name
,
error
);
return
;
}
}
}
static
void
g_ventoy_config
(
struct
gctl_req
*
req
,
struct
g_class
*
mp
,
const
char
*
verb
)
{
uint32_t
*
version
;
return
;
g_topology_assert
();
version
=
gctl_get_paraml
(
req
,
"version"
,
sizeof
(
*
version
));
if
(
version
==
NULL
)
{
gctl_error
(
req
,
"No '%s' argument."
,
"version"
);
return
;
}
if
(
*
version
!=
G_VENTOY_VERSION
)
{
gctl_error
(
req
,
"Userland and kernel parts are out of sync."
);
return
;
}
if
(
strcmp
(
verb
,
"create"
)
==
0
)
{
g_ventoy_ctl_create
(
req
,
mp
);
return
;
}
else
if
(
strcmp
(
verb
,
"destroy"
)
==
0
||
strcmp
(
verb
,
"stop"
)
==
0
)
{
g_ventoy_ctl_destroy
(
req
,
mp
);
return
;
}
gctl_error
(
req
,
"Unknown verb."
);
}
static
void
g_ventoy_dumpconf
(
struct
sbuf
*
sb
,
const
char
*
indent
,
struct
g_geom
*
gp
,
struct
g_consumer
*
cp
,
struct
g_provider
*
pp
)
{
struct
g_ventoy_softc
*
sc
;
g_topology_assert
();
sc
=
gp
->
softc
;
if
(
sc
==
NULL
)
return
;
sx_slock
(
&
sc
->
sc_disks_lock
);
if
(
pp
!=
NULL
)
{
/* Nothing here. */
}
else
if
(
cp
!=
NULL
)
{
struct
g_ventoy_disk
*
disk
;
disk
=
cp
->
private
;
if
(
disk
==
NULL
)
goto
end
;
sbuf_printf
(
sb
,
"%s<End>%jd</End>
\n
"
,
indent
,
(
intmax_t
)
disk
->
d_end
);
sbuf_printf
(
sb
,
"%s<Start>%jd</Start>
\n
"
,
indent
,
(
intmax_t
)
disk
->
d_start
);
}
else
{
sbuf_printf
(
sb
,
"%s<ID>%u</ID>
\n
"
,
indent
,
(
u_int
)
sc
->
sc_id
);
sbuf_printf
(
sb
,
"%s<Type>"
,
indent
);
switch
(
sc
->
sc_type
)
{
case
G_VENTOY_TYPE_AUTOMATIC
:
sbuf_cat
(
sb
,
"AUTOMATIC"
);
break
;
case
G_VENTOY_TYPE_MANUAL
:
sbuf_cat
(
sb
,
"MANUAL"
);
break
;
default:
sbuf_cat
(
sb
,
"UNKNOWN"
);
break
;
}
sbuf_cat
(
sb
,
"</Type>
\n
"
);
sbuf_printf
(
sb
,
"%s<Status>Total=%u, Online=%u</Status>
\n
"
,
indent
,
sc
->
sc_ndisks
,
g_ventoy_nvalid
(
sc
));
sbuf_printf
(
sb
,
"%s<State>"
,
indent
);
if
(
sc
->
sc_provider
!=
NULL
&&
sc
->
sc_provider
->
error
==
0
)
sbuf_cat
(
sb
,
"UP"
);
else
sbuf_cat
(
sb
,
"DOWN"
);
sbuf_cat
(
sb
,
"</State>
\n
"
);
}
end:
sx_sunlock
(
&
sc
->
sc_disks_lock
);
}
DECLARE_GEOM_CLASS
(
g_ventoy_class
,
g_ventoy
);
//MODULE_VERSION(geom_ventoy, 0);
Unix/ventoy_unix_src/FreeBSD/geom_ventoy_src/14.x/sys/geom/ventoy/g_ventoy.h
0 → 100644
View file @
4527e1db
/*-
* SPDX-License-Identifier: BSD-2-Clause-FreeBSD
*
* Copyright (c) 2020 longpanda <admin@ventoy.net>
* Copyright (c) 2004-2005 Pawel Jakub Dawidek <pjd@FreeBSD.org>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* $FreeBSD$
*/
#ifndef _G_VENTOY_H_
#define _G_VENTOY_H_
#include <sys/endian.h>
#define G_VENTOY_CLASS_NAME "VENTOY"
#define G_VENTOY_MAGIC "GEOM::VENTOY"
/*
* Version history:
* 1 - Initial version number.
* 2 - Added 'stop' command to gconcat(8).
* 3 - Added md_provider field to metadata and '-h' option to gconcat(8).
* 4 - Added md_provsize field to metadata.
*/
#define G_VENTOY_VERSION 4
#ifdef _KERNEL
#define G_VENTOY_TYPE_MANUAL 0
#define G_VENTOY_TYPE_AUTOMATIC 1
#define G_DEBUG(...) if (bootverbose) printf(__VA_ARGS__)
#define G_VENTOY_DEBUG(lvl, ...) if (g_ventoy_debug) printf(__VA_ARGS__)
#define G_VENTOY_LOGREQ(bp, ...) if (g_ventoy_debug) printf(__VA_ARGS__)
struct
g_ventoy_disk
{
TAILQ_ENTRY
(
g_ventoy_disk
)
d_next
;
struct
g_consumer
*
d_consumer
;
struct
g_ventoy_softc
*
d_softc
;
off_t
d_start
;
off_t
d_end
;
off_t
d_map_start
;
off_t
d_map_end
;
int
d_candelete
;
int
d_removed
;
bool
d_hardcoded
;
};
struct
g_ventoy_softc
{
u_int
sc_type
;
/* provider type */
struct
g_geom
*
sc_geom
;
struct
g_provider
*
sc_provider
;
uint32_t
sc_id
;
/* concat unique ID */
uint16_t
sc_ndisks
;
TAILQ_HEAD
(
g_ventoy_disks
,
g_ventoy_disk
)
sc_disks
;
struct
mtx
sc_completion_lock
;
/* synchronizes cross-boundary IOs */
struct
sx
sc_disks_lock
;
/* synchronizes modification of sc_disks */
};
#define sc_name sc_geom->name
#pragma pack(1)
#define VENTOY_UNIX_SEG_MAGIC0 0x11223344
#define VENTOY_UNIX_SEG_MAGIC1 0x55667788
#define VENTOY_UNIX_SEG_MAGIC2 0x99aabbcc
#define VENTOY_UNIX_SEG_MAGIC3 0xddeeff00
#define VENTOY_UNIX_MAX_SEGNUM 40960
struct
g_ventoy_seg
{
uint64_t
seg_start_bytes
;
uint64_t
seg_end_bytes
;
};
struct
g_ventoy_map
{
uint32_t
magic1
[
4
];
uint32_t
magic2
[
4
];
uint64_t
segnum
;
uint64_t
disksize
;
uint8_t
diskuuid
[
16
];
struct
g_ventoy_seg
seglist
[
VENTOY_UNIX_MAX_SEGNUM
];
uint32_t
magic3
[
4
];
};
#pragma pack()
#define VENTOY_MAP_VALID(magic2) \
(magic2[0] == VENTOY_UNIX_SEG_MAGIC0 && magic2[1] == VENTOY_UNIX_SEG_MAGIC1 && magic2[2] == VENTOY_UNIX_SEG_MAGIC2 && magic2[3] == VENTOY_UNIX_SEG_MAGIC3)
#endif
/* _KERNEL */
struct
g_ventoy_metadata
{
char
md_magic
[
16
];
/* Magic value. */
uint32_t
md_version
;
/* Version number. */
char
md_name
[
16
];
/* Concat name. */
uint32_t
md_id
;
/* Unique ID. */
uint16_t
md_no
;
/* Disk number. */
uint16_t
md_all
;
/* Number of all disks. */
char
md_provider
[
16
];
/* Hardcoded provider. */
uint64_t
md_provsize
;
/* Provider's size. */
};
static
__inline
void
ventoy_metadata_encode
(
const
struct
g_ventoy_metadata
*
md
,
u_char
*
data
)
{
bcopy
(
md
->
md_magic
,
data
,
sizeof
(
md
->
md_magic
));
le32enc
(
data
+
16
,
md
->
md_version
);
bcopy
(
md
->
md_name
,
data
+
20
,
sizeof
(
md
->
md_name
));
le32enc
(
data
+
36
,
md
->
md_id
);
le16enc
(
data
+
40
,
md
->
md_no
);
le16enc
(
data
+
42
,
md
->
md_all
);
bcopy
(
md
->
md_provider
,
data
+
44
,
sizeof
(
md
->
md_provider
));
le64enc
(
data
+
60
,
md
->
md_provsize
);
}
static
__inline
void
ventoy_metadata_decode
(
const
u_char
*
data
,
struct
g_ventoy_metadata
*
md
)
{
bcopy
(
data
,
md
->
md_magic
,
sizeof
(
md
->
md_magic
));
md
->
md_version
=
le32dec
(
data
+
16
);
bcopy
(
data
+
20
,
md
->
md_name
,
sizeof
(
md
->
md_name
));
md
->
md_id
=
le32dec
(
data
+
36
);
md
->
md_no
=
le16dec
(
data
+
40
);
md
->
md_all
=
le16dec
(
data
+
42
);
bcopy
(
data
+
44
,
md
->
md_provider
,
sizeof
(
md
->
md_provider
));
md
->
md_provsize
=
le64dec
(
data
+
60
);
}
#endif
/* _G_VENTOY_H_ */
Unix/ventoy_unix_src/FreeBSD/geom_ventoy_src/14.x/sys/modules/geom/geom_ventoy/Makefile
0 → 100644
View file @
4527e1db
# $FreeBSD$
.PATH
:
${SRCTOP}/sys/geom/ventoy
KMOD
=
geom_ventoy
SRCS
=
g_ventoy.c
.
include
<bsd.kmod.mk>
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment