@@ -892,6 +892,7 @@ typedef struct destroy_cbdata {
892
892
boolean_t cb_parsable ;
893
893
boolean_t cb_dryrun ;
894
894
nvlist_t * cb_nvl ;
895
+ nvlist_t * cb_batchedsnaps ;
895
896
896
897
/* first snap in contiguous run */
897
898
char * cb_firstsnap ;
@@ -988,9 +989,27 @@ destroy_callback(zfs_handle_t *zhp, void *data)
988
989
zfs_close (zhp );
989
990
return (0 );
990
991
}
992
+ if (cb -> cb_dryrun ) {
993
+ zfs_close (zhp );
994
+ return (0 );
995
+ }
996
+
997
+ /*
998
+ * We batch up all contiguous snapshots (even of different
999
+ * filesystems) and destroy them with one ioctl. We can't
1000
+ * simply do all snap deletions and then all fs deletions,
1001
+ * because we must delete a clone before its origin.
1002
+ */
1003
+ if (zfs_get_type (zhp ) == ZFS_TYPE_SNAPSHOT ) {
1004
+ fnvlist_add_boolean (cb -> cb_batchedsnaps , name );
1005
+ } else {
1006
+ int error = zfs_destroy_snaps_nvl (g_zfs ,
1007
+ cb -> cb_batchedsnaps , B_FALSE );
1008
+ fnvlist_free (cb -> cb_batchedsnaps );
1009
+ cb -> cb_batchedsnaps = fnvlist_alloc ();
991
1010
992
- if (! cb -> cb_dryrun ) {
993
- if ( zfs_unmount (zhp , NULL , cb -> cb_force ? MS_FORCE : 0 ) != 0 ||
1011
+ if (error != 0 ||
1012
+ zfs_unmount (zhp , NULL , cb -> cb_force ? MS_FORCE : 0 ) != 0 ||
994
1013
zfs_destroy (zhp , cb -> cb_defer_destroy ) != 0 ) {
995
1014
zfs_close (zhp );
996
1015
return (-1 );
@@ -1146,8 +1165,10 @@ static int
1146
1165
zfs_do_destroy (int argc , char * * argv )
1147
1166
{
1148
1167
destroy_cbdata_t cb = { 0 };
1168
+ int rv = 0 ;
1169
+ int err = 0 ;
1149
1170
int c ;
1150
- zfs_handle_t * zhp ;
1171
+ zfs_handle_t * zhp = NULL ;
1151
1172
char * at ;
1152
1173
zfs_type_t type = ZFS_TYPE_DATASET ;
1153
1174
@@ -1201,11 +1222,9 @@ zfs_do_destroy(int argc, char **argv)
1201
1222
1202
1223
at = strchr (argv [0 ], '@' );
1203
1224
if (at != NULL ) {
1204
- int err = 0 ;
1205
1225
1206
1226
/* Build the list of snaps to destroy in cb_nvl. */
1207
- if (nvlist_alloc (& cb .cb_nvl , NV_UNIQUE_NAME , 0 ) != 0 )
1208
- nomem ();
1227
+ cb .cb_nvl = fnvlist_alloc ();
1209
1228
1210
1229
* at = '\0' ;
1211
1230
zhp = zfs_open (g_zfs , argv [0 ],
@@ -1216,17 +1235,15 @@ zfs_do_destroy(int argc, char **argv)
1216
1235
cb .cb_snapspec = at + 1 ;
1217
1236
if (gather_snapshots (zfs_handle_dup (zhp ), & cb ) != 0 ||
1218
1237
cb .cb_error ) {
1219
- zfs_close (zhp );
1220
- nvlist_free (cb .cb_nvl );
1221
- return (1 );
1238
+ rv = 1 ;
1239
+ goto out ;
1222
1240
}
1223
1241
1224
1242
if (nvlist_empty (cb .cb_nvl )) {
1225
1243
(void ) fprintf (stderr , gettext ("could not find any "
1226
1244
"snapshots to destroy; check snapshot names.\n" ));
1227
- zfs_close (zhp );
1228
- nvlist_free (cb .cb_nvl );
1229
- return (1 );
1245
+ rv = 1 ;
1246
+ goto out ;
1230
1247
}
1231
1248
1232
1249
if (cb .cb_verbose ) {
@@ -1245,18 +1262,26 @@ zfs_do_destroy(int argc, char **argv)
1245
1262
}
1246
1263
1247
1264
if (!cb .cb_dryrun ) {
1248
- if (cb .cb_doclones )
1265
+ if (cb .cb_doclones ) {
1266
+ cb .cb_batchedsnaps = fnvlist_alloc ();
1249
1267
err = destroy_clones (& cb );
1268
+ if (err == 0 ) {
1269
+ err = zfs_destroy_snaps_nvl (g_zfs ,
1270
+ cb .cb_batchedsnaps , B_FALSE );
1271
+ }
1272
+ if (err != 0 ) {
1273
+ rv = 1 ;
1274
+ goto out ;
1275
+ }
1276
+ }
1250
1277
if (err == 0 ) {
1251
- err = zfs_destroy_snaps_nvl (zhp , cb .cb_nvl ,
1278
+ err = zfs_destroy_snaps_nvl (g_zfs , cb .cb_nvl ,
1252
1279
cb .cb_defer_destroy );
1253
1280
}
1254
1281
}
1255
1282
1256
- zfs_close (zhp );
1257
- nvlist_free (cb .cb_nvl );
1258
1283
if (err != 0 )
1259
- return ( 1 ) ;
1284
+ rv = 1 ;
1260
1285
} else {
1261
1286
/* Open the given dataset */
1262
1287
if ((zhp = zfs_open (g_zfs , argv [0 ], type )) == NULL )
@@ -1277,8 +1302,8 @@ zfs_do_destroy(int argc, char **argv)
1277
1302
zfs_get_name (zhp ));
1278
1303
(void ) fprintf (stderr , gettext ("use 'zpool destroy %s' "
1279
1304
"to destroy the pool itself\n" ), zfs_get_name (zhp ));
1280
- zfs_close ( zhp ) ;
1281
- return ( 1 ) ;
1305
+ rv = 1 ;
1306
+ goto out ;
1282
1307
}
1283
1308
1284
1309
/*
@@ -1288,30 +1313,42 @@ zfs_do_destroy(int argc, char **argv)
1288
1313
if (!cb .cb_doclones &&
1289
1314
zfs_iter_dependents (zhp , B_TRUE , destroy_check_dependent ,
1290
1315
& cb ) != 0 ) {
1291
- zfs_close ( zhp ) ;
1292
- return ( 1 ) ;
1316
+ rv = 1 ;
1317
+ goto out ;
1293
1318
}
1294
1319
1295
1320
if (cb .cb_error ) {
1296
- zfs_close ( zhp ) ;
1297
- return ( 1 ) ;
1321
+ rv = 1 ;
1322
+ goto out ;
1298
1323
}
1299
1324
1325
+ cb .cb_batchedsnaps = fnvlist_alloc ();
1300
1326
if (zfs_iter_dependents (zhp , B_FALSE , destroy_callback ,
1301
1327
& cb ) != 0 ) {
1302
- zfs_close ( zhp ) ;
1303
- return ( 1 ) ;
1328
+ rv = 1 ;
1329
+ goto out ;
1304
1330
}
1305
1331
1306
1332
/*
1307
1333
* Do the real thing. The callback will close the
1308
1334
* handle regardless of whether it succeeds or not.
1309
1335
*/
1310
- if (destroy_callback (zhp , & cb ) != 0 )
1311
- return (1 );
1336
+ err = destroy_callback (zhp , & cb );
1337
+ zhp = NULL ;
1338
+ if (err == 0 ) {
1339
+ err = zfs_destroy_snaps_nvl (g_zfs ,
1340
+ cb .cb_batchedsnaps , cb .cb_defer_destroy );
1341
+ }
1342
+ if (err != 0 )
1343
+ rv = 1 ;
1312
1344
}
1313
1345
1314
- return (0 );
1346
+ out :
1347
+ fnvlist_free (cb .cb_batchedsnaps );
1348
+ fnvlist_free (cb .cb_nvl );
1349
+ if (zhp != NULL )
1350
+ zfs_close (zhp );
1351
+ return (rv );
1315
1352
}
1316
1353
1317
1354
static boolean_t
@@ -5081,28 +5118,12 @@ zfs_do_allow_unallow_impl(int argc, char **argv, boolean_t un)
5081
5118
return (error );
5082
5119
}
5083
5120
5084
- /*
5085
- * zfs allow [-r] [-t] <tag> <snap> ...
5086
- *
5087
- * -r Recursively hold
5088
- * -t Temporary hold (hidden option)
5089
- *
5090
- * Apply a user-hold with the given tag to the list of snapshots.
5091
- */
5092
5121
static int
5093
5122
zfs_do_allow (int argc , char * * argv )
5094
5123
{
5095
5124
return (zfs_do_allow_unallow_impl (argc , argv , B_FALSE ));
5096
5125
}
5097
5126
5098
- /*
5099
- * zfs unallow [-r] [-t] <tag> <snap> ...
5100
- *
5101
- * -r Recursively hold
5102
- * -t Temporary hold (hidden option)
5103
- *
5104
- * Apply a user-hold with the given tag to the list of snapshots.
5105
- */
5106
5127
static int
5107
5128
zfs_do_unallow (int argc , char * * argv )
5108
5129
{
@@ -5116,7 +5137,6 @@ zfs_do_hold_rele_impl(int argc, char **argv, boolean_t holding)
5116
5137
int i ;
5117
5138
const char * tag ;
5118
5139
boolean_t recursive = B_FALSE ;
5119
- boolean_t temphold = B_FALSE ;
5120
5140
const char * opts = holding ? "rt" : "r" ;
5121
5141
int c ;
5122
5142
@@ -5126,9 +5146,6 @@ zfs_do_hold_rele_impl(int argc, char **argv, boolean_t holding)
5126
5146
case 'r' :
5127
5147
recursive = B_TRUE ;
5128
5148
break ;
5129
- case 't' :
5130
- temphold = B_TRUE ;
5131
- break ;
5132
5149
case '?' :
5133
5150
(void ) fprintf (stderr , gettext ("invalid option '%c'\n" ),
5134
5151
optopt );
@@ -5177,7 +5194,7 @@ zfs_do_hold_rele_impl(int argc, char **argv, boolean_t holding)
5177
5194
}
5178
5195
if (holding ) {
5179
5196
if (zfs_hold (zhp , delim + 1 , tag , recursive ,
5180
- temphold , B_FALSE , -1 , 0 , 0 ) != 0 )
5197
+ B_FALSE , -1 ) != 0 )
5181
5198
++ errors ;
5182
5199
} else {
5183
5200
if (zfs_release (zhp , delim + 1 , tag , recursive ) != 0 )
@@ -5193,7 +5210,6 @@ zfs_do_hold_rele_impl(int argc, char **argv, boolean_t holding)
5193
5210
* zfs hold [-r] [-t] <tag> <snap> ...
5194
5211
*
5195
5212
* -r Recursively hold
5196
- * -t Temporary hold (hidden option)
5197
5213
*
5198
5214
* Apply a user-hold with the given tag to the list of snapshots.
5199
5215
*/
0 commit comments