Commit | Line | Data |
---|---|---|
2910a90c | 1 | /* |
3148f677 | 2 | * Copyright (c) 2011-2015 The DragonFly Project. All rights reserved. |
2910a90c MD |
3 | * |
4 | * This code is derived from software contributed to The DragonFly Project | |
5 | * by Matthew Dillon <dillon@dragonflybsd.org> | |
6 | * by Venkatesh Srinivas <vsrinivas@dragonflybsd.org> | |
7 | * | |
8 | * Redistribution and use in source and binary forms, with or without | |
9 | * modification, are permitted provided that the following conditions | |
10 | * are met: | |
11 | * | |
12 | * 1. Redistributions of source code must retain the above copyright | |
13 | * notice, this list of conditions and the following disclaimer. | |
14 | * 2. Redistributions in binary form must reproduce the above copyright | |
15 | * notice, this list of conditions and the following disclaimer in | |
16 | * the documentation and/or other materials provided with the | |
17 | * distribution. | |
18 | * 3. Neither the name of The DragonFly Project nor the names of its | |
19 | * contributors may be used to endorse or promote products derived | |
20 | * from this software without specific, prior written permission. | |
21 | * | |
22 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | |
23 | * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | |
24 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS | |
25 | * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE | |
26 | * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, | |
27 | * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING, | |
28 | * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | |
29 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED | |
30 | * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, | |
31 | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT | |
32 | * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | |
33 | * SUCH DAMAGE. | |
34 | */ | |
35 | /* | |
36 | * Ioctl Functions. | |
37 | * | |
38 | * WARNING! The ioctl functions which manipulate the connection state need | |
39 | * to be able to run without deadlock on the volume's chain lock. | |
40 | * Most of these functions use a separate lock. | |
41 | */ | |
42 | ||
43 | #include "hammer2.h" | |
44 | ||
ae183399 | 45 | static int hammer2_ioctl_version_get(hammer2_inode_t *ip, void *data); |
1a34728c MD |
46 | static int hammer2_ioctl_recluster(hammer2_inode_t *ip, void *data); |
47 | static int hammer2_ioctl_remote_scan(hammer2_inode_t *ip, void *data); | |
ae183399 MD |
48 | static int hammer2_ioctl_remote_add(hammer2_inode_t *ip, void *data); |
49 | static int hammer2_ioctl_remote_del(hammer2_inode_t *ip, void *data); | |
50 | static int hammer2_ioctl_remote_rep(hammer2_inode_t *ip, void *data); | |
51 | static int hammer2_ioctl_socket_get(hammer2_inode_t *ip, void *data); | |
52 | static int hammer2_ioctl_socket_set(hammer2_inode_t *ip, void *data); | |
53 | static int hammer2_ioctl_pfs_get(hammer2_inode_t *ip, void *data); | |
458ecb1b | 54 | static int hammer2_ioctl_pfs_lookup(hammer2_inode_t *ip, void *data); |
ae183399 | 55 | static int hammer2_ioctl_pfs_create(hammer2_inode_t *ip, void *data); |
a864c5d9 | 56 | static int hammer2_ioctl_pfs_snapshot(hammer2_inode_t *ip, void *data); |
ae183399 | 57 | static int hammer2_ioctl_pfs_delete(hammer2_inode_t *ip, void *data); |
344d4f82 MD |
58 | static int hammer2_ioctl_inode_get(hammer2_inode_t *ip, void *data); |
59 | static int hammer2_ioctl_inode_set(hammer2_inode_t *ip, void *data); | |
03188ed8 | 60 | static int hammer2_ioctl_debug_dump(hammer2_inode_t *ip); |
355d67fc MD |
61 | //static int hammer2_ioctl_inode_comp_set(hammer2_inode_t *ip, void *data); |
62 | //static int hammer2_ioctl_inode_comp_rec_set(hammer2_inode_t *ip, void *data); | |
63 | //static int hammer2_ioctl_inode_comp_rec_set2(hammer2_inode_t *ip, void *data); | |
3148f677 | 64 | static int hammer2_ioctl_bulkfree_scan(hammer2_inode_t *ip, void *data); |
2910a90c MD |
65 | |
66 | int | |
67 | hammer2_ioctl(hammer2_inode_t *ip, u_long com, void *data, int fflag, | |
68 | struct ucred *cred) | |
69 | { | |
70 | int error; | |
71 | ||
72 | /* | |
73 | * Standard root cred checks, will be selectively ignored below | |
74 | * for ioctls that do not require root creds. | |
75 | */ | |
76 | error = priv_check_cred(cred, PRIV_HAMMER_IOCTL, 0); | |
77 | ||
78 | switch(com) { | |
ae183399 MD |
79 | case HAMMER2IOC_VERSION_GET: |
80 | error = hammer2_ioctl_version_get(ip, data); | |
2910a90c | 81 | break; |
1a34728c | 82 | case HAMMER2IOC_RECLUSTER: |
2910a90c | 83 | if (error == 0) |
1a34728c MD |
84 | error = hammer2_ioctl_recluster(ip, data); |
85 | break; | |
86 | case HAMMER2IOC_REMOTE_SCAN: | |
87 | if (error == 0) | |
88 | error = hammer2_ioctl_remote_scan(ip, data); | |
2910a90c | 89 | break; |
ae183399 | 90 | case HAMMER2IOC_REMOTE_ADD: |
2910a90c | 91 | if (error == 0) |
ae183399 | 92 | error = hammer2_ioctl_remote_add(ip, data); |
2910a90c | 93 | break; |
ae183399 | 94 | case HAMMER2IOC_REMOTE_DEL: |
2910a90c | 95 | if (error == 0) |
ae183399 | 96 | error = hammer2_ioctl_remote_del(ip, data); |
2910a90c | 97 | break; |
ae183399 | 98 | case HAMMER2IOC_REMOTE_REP: |
2910a90c | 99 | if (error == 0) |
ae183399 | 100 | error = hammer2_ioctl_remote_rep(ip, data); |
2910a90c | 101 | break; |
ae183399 | 102 | case HAMMER2IOC_SOCKET_GET: |
2910a90c | 103 | if (error == 0) |
ae183399 | 104 | error = hammer2_ioctl_socket_get(ip, data); |
2910a90c | 105 | break; |
ae183399 MD |
106 | case HAMMER2IOC_SOCKET_SET: |
107 | if (error == 0) | |
108 | error = hammer2_ioctl_socket_set(ip, data); | |
109 | break; | |
110 | case HAMMER2IOC_PFS_GET: | |
2910a90c | 111 | if (error == 0) |
ae183399 MD |
112 | error = hammer2_ioctl_pfs_get(ip, data); |
113 | break; | |
458ecb1b MD |
114 | case HAMMER2IOC_PFS_LOOKUP: |
115 | if (error == 0) | |
116 | error = hammer2_ioctl_pfs_lookup(ip, data); | |
117 | break; | |
ae183399 MD |
118 | case HAMMER2IOC_PFS_CREATE: |
119 | if (error == 0) | |
120 | error = hammer2_ioctl_pfs_create(ip, data); | |
121 | break; | |
122 | case HAMMER2IOC_PFS_DELETE: | |
123 | if (error == 0) | |
124 | error = hammer2_ioctl_pfs_delete(ip, data); | |
2910a90c | 125 | break; |
a864c5d9 MD |
126 | case HAMMER2IOC_PFS_SNAPSHOT: |
127 | if (error == 0) | |
128 | error = hammer2_ioctl_pfs_snapshot(ip, data); | |
129 | break; | |
344d4f82 MD |
130 | case HAMMER2IOC_INODE_GET: |
131 | error = hammer2_ioctl_inode_get(ip, data); | |
132 | break; | |
133 | case HAMMER2IOC_INODE_SET: | |
134 | if (error == 0) | |
135 | error = hammer2_ioctl_inode_set(ip, data); | |
136 | break; | |
3148f677 MD |
137 | case HAMMER2IOC_BULKFREE_SCAN: |
138 | error = hammer2_ioctl_bulkfree_scan(ip, data); | |
139 | break; | |
355d67fc MD |
140 | /*case HAMMER2IOC_INODE_COMP_SET: |
141 | error = hammer2_ioctl_inode_comp_set(ip, data); | |
142 | break; | |
143 | case HAMMER2IOC_INODE_COMP_REC_SET: | |
144 | error = hammer2_ioctl_inode_comp_rec_set(ip, data); | |
145 | break; | |
146 | case HAMMER2IOC_INODE_COMP_REC_SET2: | |
147 | error = hammer2_ioctl_inode_comp_rec_set2(ip, data); | |
148 | break;*/ | |
03188ed8 MD |
149 | case HAMMER2IOC_DEBUG_DUMP: |
150 | error = hammer2_ioctl_debug_dump(ip); | |
151 | break; | |
2910a90c MD |
152 | default: |
153 | error = EOPNOTSUPP; | |
154 | break; | |
155 | } | |
156 | return (error); | |
157 | } | |
158 | ||
159 | /* | |
160 | * Retrieve version and basic info | |
161 | */ | |
162 | static int | |
ae183399 | 163 | hammer2_ioctl_version_get(hammer2_inode_t *ip, void *data) |
2910a90c | 164 | { |
2910a90c | 165 | hammer2_ioc_version_t *version = data; |
01d71aa5 | 166 | hammer2_dev_t *hmp; |
2910a90c | 167 | |
01d71aa5 MD |
168 | hmp = ip->pmp->pfs_hmps[0]; |
169 | if (hmp) | |
170 | version->version = hmp->voldata.version; | |
171 | else | |
172 | version->version = -1; | |
2910a90c MD |
173 | return 0; |
174 | } | |
175 | ||
1a34728c MD |
176 | static int |
177 | hammer2_ioctl_recluster(hammer2_inode_t *ip, void *data) | |
178 | { | |
179 | hammer2_ioc_recluster_t *recl = data; | |
180 | struct file *fp; | |
063639ba MD |
181 | hammer2_cluster_t *cluster; |
182 | int error; | |
1a34728c MD |
183 | |
184 | fp = holdfp(curproc->p_fd, recl->fd, -1); | |
185 | if (fp) { | |
fe73aa5d | 186 | kprintf("reconnect to cluster: XXX "); |
063639ba MD |
187 | cluster = &ip->pmp->iroot->cluster; |
188 | if (cluster->nchains != 1 || cluster->focus == NULL) { | |
189 | kprintf("not a local device mount\n"); | |
190 | error = EINVAL; | |
191 | } else { | |
192 | hammer2_cluster_reconnect(cluster->focus->hmp, fp); | |
193 | kprintf("ok\n"); | |
194 | error = 0; | |
195 | } | |
1a34728c | 196 | } else { |
063639ba | 197 | error = EINVAL; |
1a34728c | 198 | } |
063639ba | 199 | return error; |
1a34728c MD |
200 | } |
201 | ||
2910a90c MD |
202 | /* |
203 | * Retrieve information about a remote | |
204 | */ | |
205 | static int | |
1a34728c | 206 | hammer2_ioctl_remote_scan(hammer2_inode_t *ip, void *data) |
2910a90c | 207 | { |
01d71aa5 | 208 | hammer2_dev_t *hmp; |
2910a90c MD |
209 | hammer2_ioc_remote_t *remote = data; |
210 | int copyid = remote->copyid; | |
211 | ||
01d71aa5 MD |
212 | hmp = ip->pmp->pfs_hmps[0]; |
213 | if (hmp == NULL) | |
214 | return (EINVAL); | |
215 | ||
2910a90c MD |
216 | if (copyid < 0 || copyid >= HAMMER2_COPYID_COUNT) |
217 | return (EINVAL); | |
218 | ||
219 | hammer2_voldata_lock(hmp); | |
220 | remote->copy1 = hmp->voldata.copyinfo[copyid]; | |
50456506 | 221 | hammer2_voldata_unlock(hmp); |
2910a90c MD |
222 | |
223 | /* | |
224 | * Adjust nextid (GET only) | |
225 | */ | |
226 | while (++copyid < HAMMER2_COPYID_COUNT && | |
227 | hmp->voldata.copyinfo[copyid].copyid == 0) { | |
1a34728c | 228 | ; |
2910a90c MD |
229 | } |
230 | if (copyid == HAMMER2_COPYID_COUNT) | |
231 | remote->nextid = -1; | |
232 | else | |
233 | remote->nextid = copyid; | |
234 | ||
235 | return(0); | |
236 | } | |
237 | ||
238 | /* | |
239 | * Add new remote entry | |
240 | */ | |
241 | static int | |
ae183399 | 242 | hammer2_ioctl_remote_add(hammer2_inode_t *ip, void *data) |
2910a90c | 243 | { |
2910a90c | 244 | hammer2_ioc_remote_t *remote = data; |
506bd6d1 MD |
245 | hammer2_pfs_t *pmp = ip->pmp; |
246 | hammer2_dev_t *hmp; | |
2910a90c MD |
247 | int copyid = remote->copyid; |
248 | int error = 0; | |
249 | ||
01d71aa5 MD |
250 | hmp = pmp->pfs_hmps[0]; |
251 | if (hmp == NULL) | |
252 | return (EINVAL); | |
2910a90c MD |
253 | if (copyid >= HAMMER2_COPYID_COUNT) |
254 | return (EINVAL); | |
255 | ||
256 | hammer2_voldata_lock(hmp); | |
257 | if (copyid < 0) { | |
258 | for (copyid = 1; copyid < HAMMER2_COPYID_COUNT; ++copyid) { | |
259 | if (hmp->voldata.copyinfo[copyid].copyid == 0) | |
260 | break; | |
261 | } | |
262 | if (copyid == HAMMER2_COPYID_COUNT) { | |
263 | error = ENOSPC; | |
264 | goto failed; | |
265 | } | |
266 | } | |
50456506 | 267 | hammer2_voldata_modify(hmp); |
2910a90c MD |
268 | remote->copy1.copyid = copyid; |
269 | hmp->voldata.copyinfo[copyid] = remote->copy1; | |
063639ba | 270 | hammer2_volconf_update(hmp, copyid); |
2910a90c | 271 | failed: |
50456506 | 272 | hammer2_voldata_unlock(hmp); |
2910a90c MD |
273 | return (error); |
274 | } | |
275 | ||
276 | /* | |
277 | * Delete existing remote entry | |
278 | */ | |
279 | static int | |
ae183399 | 280 | hammer2_ioctl_remote_del(hammer2_inode_t *ip, void *data) |
2910a90c | 281 | { |
2910a90c | 282 | hammer2_ioc_remote_t *remote = data; |
506bd6d1 MD |
283 | hammer2_pfs_t *pmp = ip->pmp; |
284 | hammer2_dev_t *hmp; | |
2910a90c MD |
285 | int copyid = remote->copyid; |
286 | int error = 0; | |
287 | ||
01d71aa5 MD |
288 | hmp = pmp->pfs_hmps[0]; |
289 | if (hmp == NULL) | |
290 | return (EINVAL); | |
2910a90c MD |
291 | if (copyid >= HAMMER2_COPYID_COUNT) |
292 | return (EINVAL); | |
293 | remote->copy1.path[sizeof(remote->copy1.path) - 1] = 0; | |
294 | hammer2_voldata_lock(hmp); | |
295 | if (copyid < 0) { | |
296 | for (copyid = 1; copyid < HAMMER2_COPYID_COUNT; ++copyid) { | |
297 | if (hmp->voldata.copyinfo[copyid].copyid == 0) | |
298 | continue; | |
299 | if (strcmp(remote->copy1.path, | |
300 | hmp->voldata.copyinfo[copyid].path) == 0) { | |
301 | break; | |
302 | } | |
303 | } | |
304 | if (copyid == HAMMER2_COPYID_COUNT) { | |
305 | error = ENOENT; | |
306 | goto failed; | |
307 | } | |
308 | } | |
50456506 | 309 | hammer2_voldata_modify(hmp); |
2910a90c | 310 | hmp->voldata.copyinfo[copyid].copyid = 0; |
063639ba | 311 | hammer2_volconf_update(hmp, copyid); |
2910a90c | 312 | failed: |
50456506 | 313 | hammer2_voldata_unlock(hmp); |
2910a90c MD |
314 | return (error); |
315 | } | |
316 | ||
317 | /* | |
318 | * Replace existing remote entry | |
319 | */ | |
320 | static int | |
ae183399 | 321 | hammer2_ioctl_remote_rep(hammer2_inode_t *ip, void *data) |
2910a90c | 322 | { |
2910a90c | 323 | hammer2_ioc_remote_t *remote = data; |
506bd6d1 | 324 | hammer2_dev_t *hmp; |
2910a90c MD |
325 | int copyid = remote->copyid; |
326 | ||
01d71aa5 MD |
327 | hmp = ip->pmp->pfs_hmps[0]; |
328 | if (hmp == NULL) | |
329 | return (EINVAL); | |
2910a90c MD |
330 | if (copyid < 0 || copyid >= HAMMER2_COPYID_COUNT) |
331 | return (EINVAL); | |
332 | ||
333 | hammer2_voldata_lock(hmp); | |
50456506 | 334 | hammer2_voldata_modify(hmp); |
063639ba | 335 | /*hammer2_volconf_update(hmp, copyid);*/ |
50456506 | 336 | hammer2_voldata_unlock(hmp); |
2910a90c MD |
337 | |
338 | return(0); | |
339 | } | |
340 | ||
341 | /* | |
342 | * Retrieve communications socket | |
343 | */ | |
344 | static int | |
ae183399 | 345 | hammer2_ioctl_socket_get(hammer2_inode_t *ip, void *data) |
2910a90c MD |
346 | { |
347 | return (EOPNOTSUPP); | |
348 | } | |
349 | ||
350 | /* | |
351 | * Set communications socket for connection | |
352 | */ | |
353 | static int | |
ae183399 | 354 | hammer2_ioctl_socket_set(hammer2_inode_t *ip, void *data) |
2910a90c | 355 | { |
2910a90c | 356 | hammer2_ioc_remote_t *remote = data; |
506bd6d1 | 357 | hammer2_dev_t *hmp; |
2910a90c MD |
358 | int copyid = remote->copyid; |
359 | ||
01d71aa5 MD |
360 | hmp = ip->pmp->pfs_hmps[0]; |
361 | if (hmp == NULL) | |
362 | return (EINVAL); | |
2910a90c MD |
363 | if (copyid < 0 || copyid >= HAMMER2_COPYID_COUNT) |
364 | return (EINVAL); | |
365 | ||
366 | hammer2_voldata_lock(hmp); | |
50456506 | 367 | hammer2_voldata_unlock(hmp); |
2910a90c MD |
368 | |
369 | return(0); | |
370 | } | |
ae183399 MD |
371 | |
372 | /* | |
a864c5d9 MD |
373 | * Used to scan and retrieve PFS information. PFS's are directories under |
374 | * the super-root. | |
375 | * | |
376 | * To scan PFSs pass name_key=0. The function will scan for the next | |
377 | * PFS and set all fields, as well as set name_next to the next key. | |
378 | * When no PFSs remain, name_next is set to (hammer2_key_t)-1. | |
379 | * | |
b7add675 MD |
380 | * To retrieve a particular PFS by key, specify the key but note that |
381 | * the ioctl will return the lowest key >= specified_key, so the caller | |
382 | * must verify the key. | |
383 | * | |
a864c5d9 MD |
384 | * To retrieve the PFS associated with the file descriptor, pass |
385 | * name_key set to (hammer2_key_t)-1. | |
ae183399 MD |
386 | */ |
387 | static int | |
388 | hammer2_ioctl_pfs_get(hammer2_inode_t *ip, void *data) | |
389 | { | |
bca9f8e6 | 390 | const hammer2_inode_data_t *ripdata; |
506bd6d1 | 391 | hammer2_dev_t *hmp; |
476d2aad | 392 | hammer2_ioc_pfs_t *pfs; |
b7add675 MD |
393 | hammer2_chain_t *parent; |
394 | hammer2_chain_t *chain; | |
1897c66e | 395 | hammer2_key_t key_next; |
b7add675 MD |
396 | hammer2_key_t save_key; |
397 | int cache_index = -1; | |
476d2aad | 398 | int error; |
ae183399 | 399 | |
01d71aa5 MD |
400 | hmp = ip->pmp->pfs_hmps[0]; |
401 | if (hmp == NULL) | |
402 | return (EINVAL); | |
b7add675 | 403 | |
01d71aa5 | 404 | pfs = data; |
b7add675 | 405 | save_key = pfs->name_key; |
01d71aa5 | 406 | error = 0; |
ae183399 MD |
407 | |
408 | /* | |
b7add675 | 409 | * Setup |
ae183399 | 410 | */ |
b7add675 MD |
411 | if (save_key == (hammer2_key_t)-1) { |
412 | hammer2_inode_lock(ip->pmp->iroot, 0); | |
413 | parent = NULL; | |
414 | chain = hammer2_inode_chain(hmp->spmp->iroot, 0, | |
415 | HAMMER2_RESOLVE_ALWAYS | | |
416 | HAMMER2_RESOLVE_SHARED); | |
ae183399 | 417 | } else { |
b7add675 MD |
418 | hammer2_inode_lock(hmp->spmp->iroot, 0); |
419 | parent = hammer2_inode_chain(hmp->spmp->iroot, 0, | |
420 | HAMMER2_RESOLVE_ALWAYS | | |
421 | HAMMER2_RESOLVE_SHARED); | |
422 | chain = hammer2_chain_lookup(&parent, &key_next, | |
423 | pfs->name_key, HAMMER2_KEY_MAX, | |
424 | &cache_index, | |
425 | HAMMER2_LOOKUP_SHARED); | |
ae183399 | 426 | } |
9b6b3df4 | 427 | |
b7add675 MD |
428 | /* |
429 | * Locate next PFS | |
430 | */ | |
431 | while (chain) { | |
432 | if (chain->bref.type == HAMMER2_BREF_TYPE_INODE) | |
433 | break; | |
434 | if (parent == NULL) { | |
435 | hammer2_chain_unlock(chain); | |
436 | hammer2_chain_drop(chain); | |
01d71aa5 | 437 | chain = NULL; |
b7add675 MD |
438 | break; |
439 | } | |
440 | chain = hammer2_chain_next(&parent, chain, &key_next, | |
441 | key_next, HAMMER2_KEY_MAX, | |
442 | &cache_index, | |
443 | HAMMER2_LOOKUP_SHARED); | |
ae183399 | 444 | } |
b7add675 MD |
445 | |
446 | /* | |
447 | * Load the data being returned by the ioctl. | |
448 | */ | |
449 | if (chain) { | |
450 | ripdata = &chain->data->ipdata; | |
b0f58de8 MD |
451 | pfs->name_key = ripdata->meta.name_key; |
452 | pfs->pfs_type = ripdata->meta.pfs_type; | |
453 | pfs->pfs_subtype = ripdata->meta.pfs_subtype; | |
454 | pfs->pfs_clid = ripdata->meta.pfs_clid; | |
455 | pfs->pfs_fsid = ripdata->meta.pfs_fsid; | |
456 | KKASSERT(ripdata->meta.name_len < sizeof(pfs->name)); | |
457 | bcopy(ripdata->filename, pfs->name, ripdata->meta.name_len); | |
458 | pfs->name[ripdata->meta.name_len] = 0; | |
bca9f8e6 | 459 | ripdata = NULL; /* safety */ |
ae183399 MD |
460 | |
461 | /* | |
01d71aa5 | 462 | * Calculate name_next, if any. |
ae183399 | 463 | */ |
01d71aa5 | 464 | if (parent == NULL) { |
ae183399 | 465 | pfs->name_next = (hammer2_key_t)-1; |
01d71aa5 MD |
466 | } else { |
467 | chain = hammer2_chain_next(&parent, chain, &key_next, | |
468 | key_next, HAMMER2_KEY_MAX, | |
469 | &cache_index, | |
470 | HAMMER2_LOOKUP_SHARED); | |
471 | if (chain) | |
472 | pfs->name_next = chain->bref.key; | |
473 | else | |
474 | pfs->name_next = (hammer2_key_t)-1; | |
475 | } | |
ae183399 MD |
476 | } else { |
477 | pfs->name_next = (hammer2_key_t)-1; | |
478 | error = ENOENT; | |
479 | } | |
b7add675 MD |
480 | |
481 | /* | |
482 | * Cleanup | |
483 | */ | |
484 | if (chain) { | |
485 | hammer2_chain_unlock(chain); | |
486 | hammer2_chain_drop(chain); | |
487 | } | |
488 | if (parent) { | |
489 | hammer2_chain_unlock(parent); | |
490 | hammer2_chain_drop(parent); | |
491 | } | |
492 | if (save_key == (hammer2_key_t)-1) { | |
493 | hammer2_inode_unlock(ip->pmp->iroot); | |
494 | } else { | |
495 | hammer2_inode_unlock(hmp->spmp->iroot); | |
496 | } | |
0dea3156 | 497 | |
ae183399 MD |
498 | return (error); |
499 | } | |
500 | ||
458ecb1b MD |
501 | /* |
502 | * Find a specific PFS by name | |
503 | */ | |
504 | static int | |
505 | hammer2_ioctl_pfs_lookup(hammer2_inode_t *ip, void *data) | |
506 | { | |
bca9f8e6 | 507 | const hammer2_inode_data_t *ripdata; |
506bd6d1 | 508 | hammer2_dev_t *hmp; |
476d2aad | 509 | hammer2_ioc_pfs_t *pfs; |
b7add675 MD |
510 | hammer2_chain_t *parent; |
511 | hammer2_chain_t *chain; | |
1897c66e | 512 | hammer2_key_t key_next; |
458ecb1b | 513 | hammer2_key_t lhc; |
b7add675 | 514 | int cache_index = -1; |
476d2aad | 515 | int error; |
458ecb1b MD |
516 | size_t len; |
517 | ||
01d71aa5 MD |
518 | hmp = ip->pmp->pfs_hmps[0]; |
519 | if (hmp == NULL) | |
520 | return (EINVAL); | |
521 | ||
476d2aad | 522 | pfs = data; |
01d71aa5 MD |
523 | error = 0; |
524 | ||
b7add675 MD |
525 | hammer2_inode_lock(hmp->spmp->iroot, HAMMER2_RESOLVE_SHARED); |
526 | parent = hammer2_inode_chain(hmp->spmp->iroot, 0, | |
527 | HAMMER2_RESOLVE_ALWAYS | | |
528 | HAMMER2_RESOLVE_SHARED); | |
458ecb1b MD |
529 | |
530 | pfs->name[sizeof(pfs->name) - 1] = 0; | |
531 | len = strlen(pfs->name); | |
532 | lhc = hammer2_dirhash(pfs->name, len); | |
533 | ||
b7add675 | 534 | chain = hammer2_chain_lookup(&parent, &key_next, |
278ab2b2 | 535 | lhc, lhc + HAMMER2_DIRHASH_LOMASK, |
b7add675 | 536 | &cache_index, |
b8ba9690 | 537 | HAMMER2_LOOKUP_SHARED); |
b7add675 MD |
538 | while (chain) { |
539 | if (chain->bref.type == HAMMER2_BREF_TYPE_INODE) { | |
540 | ripdata = &chain->data->ipdata; | |
b0f58de8 | 541 | if (ripdata->meta.name_len == len && |
bca9f8e6 | 542 | bcmp(ripdata->filename, pfs->name, len) == 0) { |
278ab2b2 MD |
543 | break; |
544 | } | |
bca9f8e6 | 545 | ripdata = NULL; /* safety */ |
458ecb1b | 546 | } |
b7add675 | 547 | chain = hammer2_chain_next(&parent, chain, &key_next, |
1897c66e MD |
548 | key_next, |
549 | lhc + HAMMER2_DIRHASH_LOMASK, | |
b7add675 | 550 | &cache_index, |
278ab2b2 | 551 | HAMMER2_LOOKUP_SHARED); |
458ecb1b MD |
552 | } |
553 | ||
554 | /* | |
555 | * Load the data being returned by the ioctl. | |
556 | */ | |
b7add675 MD |
557 | if (chain) { |
558 | ripdata = &chain->data->ipdata; | |
b0f58de8 MD |
559 | pfs->name_key = ripdata->meta.name_key; |
560 | pfs->pfs_type = ripdata->meta.pfs_type; | |
561 | pfs->pfs_subtype = ripdata->meta.pfs_subtype; | |
562 | pfs->pfs_clid = ripdata->meta.pfs_clid; | |
563 | pfs->pfs_fsid = ripdata->meta.pfs_fsid; | |
bca9f8e6 | 564 | ripdata = NULL; |
458ecb1b | 565 | |
b7add675 MD |
566 | hammer2_chain_unlock(chain); |
567 | hammer2_chain_drop(chain); | |
458ecb1b MD |
568 | } else { |
569 | error = ENOENT; | |
570 | } | |
b7add675 MD |
571 | if (parent) { |
572 | hammer2_chain_unlock(parent); | |
573 | hammer2_chain_drop(parent); | |
574 | } | |
575 | hammer2_inode_unlock(hmp->spmp->iroot); | |
7bed8d7e | 576 | |
458ecb1b MD |
577 | return (error); |
578 | } | |
579 | ||
ae183399 MD |
580 | /* |
581 | * Create a new PFS under the super-root | |
582 | */ | |
583 | static int | |
584 | hammer2_ioctl_pfs_create(hammer2_inode_t *ip, void *data) | |
585 | { | |
476d2aad | 586 | hammer2_inode_data_t *nipdata; |
c603b86b | 587 | hammer2_chain_t *nchain; |
506bd6d1 | 588 | hammer2_dev_t *hmp; |
b02c0ae6 | 589 | hammer2_dev_t *force_local; |
476d2aad MD |
590 | hammer2_ioc_pfs_t *pfs; |
591 | hammer2_inode_t *nip; | |
e2163f5b | 592 | hammer2_tid_t mtid; |
ae183399 MD |
593 | int error; |
594 | ||
b02c0ae6 | 595 | hmp = ip->pmp->pfs_hmps[0]; /* XXX */ |
01d71aa5 MD |
596 | if (hmp == NULL) |
597 | return (EINVAL); | |
598 | ||
476d2aad MD |
599 | pfs = data; |
600 | nip = NULL; | |
601 | ||
a864c5d9 MD |
602 | if (pfs->name[0] == 0) |
603 | return(EINVAL); | |
ae183399 | 604 | pfs->name[sizeof(pfs->name) - 1] = 0; /* ensure 0-termination */ |
10252dc7 | 605 | |
3c198419 MD |
606 | if (hammer2_ioctl_pfs_lookup(ip, pfs) == 0) |
607 | return(EEXIST); | |
608 | ||
c603b86b | 609 | hammer2_trans_init(hmp->spmp, 0); |
e2163f5b | 610 | mtid = hammer2_trans_sub(hmp->spmp); |
c603b86b | 611 | nip = hammer2_inode_create(hmp->spmp->iroot, NULL, NULL, |
b7add675 | 612 | pfs->name, strlen(pfs->name), 0, |
e12ae3a5 | 613 | 1, HAMMER2_OBJTYPE_DIRECTORY, 0, |
c603b86b | 614 | HAMMER2_INSERT_PFSROOT, &error); |
ae183399 | 615 | if (error == 0) { |
c603b86b MD |
616 | hammer2_inode_modify(nip); |
617 | nchain = hammer2_inode_chain(nip, 0, HAMMER2_RESOLVE_ALWAYS); | |
3f01ebaa | 618 | hammer2_chain_modify(nchain, mtid, 0, 0); |
c603b86b MD |
619 | nipdata = &nchain->data->ipdata; |
620 | ||
621 | nip->meta.pfs_type = pfs->pfs_type; | |
622 | nip->meta.pfs_subtype = pfs->pfs_subtype; | |
623 | nip->meta.pfs_clid = pfs->pfs_clid; | |
624 | nip->meta.pfs_fsid = pfs->pfs_fsid; | |
625 | nip->meta.op_flags |= HAMMER2_OPFLAG_PFSROOT; | |
cdfd0a3e MD |
626 | |
627 | /* | |
27253552 MD |
628 | * Set default compression and check algorithm. This |
629 | * can be changed later. | |
630 | * | |
cdfd0a3e MD |
631 | * Do not allow compression on PFS's with the special name |
632 | * "boot", the boot loader can't decompress (yet). | |
633 | */ | |
c603b86b | 634 | nip->meta.comp_algo = |
27253552 | 635 | HAMMER2_ENC_ALGO(HAMMER2_COMP_NEWFS_DEFAULT); |
c603b86b | 636 | nip->meta.check_algo = |
27253552 MD |
637 | HAMMER2_ENC_ALGO( HAMMER2_CHECK_ISCSI32); |
638 | ||
639 | if (strcasecmp(pfs->name, "boot") == 0) { | |
c603b86b | 640 | nip->meta.comp_algo = |
27253552 MD |
641 | HAMMER2_ENC_ALGO(HAMMER2_COMP_AUTOZERO); |
642 | } | |
8cd26e36 | 643 | |
8cd26e36 MD |
644 | /* |
645 | * Super-root isn't mounted, fsync it | |
646 | */ | |
b02c0ae6 | 647 | hammer2_chain_unlock(nchain); |
8cd26e36 | 648 | hammer2_inode_ref(nip); |
b7add675 | 649 | hammer2_inode_unlock(nip); |
53f84d31 | 650 | hammer2_inode_chain_sync(nip); |
8cd26e36 | 651 | hammer2_inode_drop(nip); |
b02c0ae6 MD |
652 | |
653 | /* | |
654 | * We still have a ref on the chain, relock and associate | |
655 | * with an appropriate PFS. | |
656 | */ | |
657 | force_local = (hmp->hflags & HMNT2_LOCAL) ? hmp : NULL; | |
658 | ||
659 | hammer2_chain_lock(nchain, HAMMER2_RESOLVE_ALWAYS); | |
660 | nipdata = &nchain->data->ipdata; | |
661 | kprintf("ADD LOCAL PFS (IOCTL): %s\n", nipdata->filename); | |
662 | hammer2_pfsalloc(nchain, nipdata, | |
663 | nchain->bref.modify_tid, force_local); | |
664 | ||
665 | hammer2_chain_unlock(nchain); | |
666 | hammer2_chain_drop(nchain); | |
667 | ||
ae183399 | 668 | } |
c603b86b | 669 | hammer2_trans_done(hmp->spmp); |
278ab2b2 | 670 | |
ae183399 MD |
671 | return (error); |
672 | } | |
673 | ||
674 | /* | |
675 | * Destroy an existing PFS under the super-root | |
676 | */ | |
677 | static int | |
678 | hammer2_ioctl_pfs_delete(hammer2_inode_t *ip, void *data) | |
679 | { | |
ae183399 | 680 | hammer2_ioc_pfs_t *pfs = data; |
01d71aa5 MD |
681 | hammer2_dev_t *hmp; |
682 | hammer2_pfs_t *spmp; | |
e12ae3a5 MD |
683 | hammer2_xop_unlink_t *xop; |
684 | hammer2_inode_t *dip; | |
ae183399 MD |
685 | int error; |
686 | ||
e12ae3a5 MD |
687 | pfs->name[sizeof(pfs->name) - 1] = 0; /* ensure termination */ |
688 | ||
01d71aa5 MD |
689 | hmp = ip->pmp->pfs_hmps[0]; |
690 | if (hmp == NULL) | |
691 | return (EINVAL); | |
692 | ||
693 | spmp = hmp->spmp; | |
e12ae3a5 MD |
694 | dip = spmp->iroot; |
695 | hammer2_trans_init(spmp, 0); | |
b7add675 | 696 | hammer2_inode_lock(dip, 0); |
e12ae3a5 | 697 | |
e2163f5b | 698 | xop = hammer2_xop_alloc(dip, HAMMER2_XOP_MODIFYING); |
e12ae3a5 MD |
699 | hammer2_xop_setname(&xop->head, pfs->name, strlen(pfs->name)); |
700 | xop->isdir = 2; | |
701 | xop->dopermanent = 1; | |
702 | hammer2_xop_start(&xop->head, hammer2_xop_unlink); | |
703 | ||
704 | error = hammer2_xop_collect(&xop->head, 0); | |
705 | ||
b7add675 | 706 | hammer2_inode_unlock(dip); |
e12ae3a5 | 707 | hammer2_trans_done(spmp); |
a864c5d9 MD |
708 | |
709 | return (error); | |
710 | } | |
711 | ||
712 | static int | |
713 | hammer2_ioctl_pfs_snapshot(hammer2_inode_t *ip, void *data) | |
714 | { | |
a864c5d9 | 715 | hammer2_ioc_pfs_t *pfs = data; |
01d71aa5 MD |
716 | hammer2_dev_t *hmp; |
717 | hammer2_chain_t *chain; | |
e2163f5b | 718 | hammer2_tid_t mtid; |
a864c5d9 MD |
719 | int error; |
720 | ||
721 | if (pfs->name[0] == 0) | |
722 | return(EINVAL); | |
723 | if (pfs->name[sizeof(pfs->name)-1] != 0) | |
724 | return(EINVAL); | |
725 | ||
01d71aa5 MD |
726 | hmp = ip->pmp->pfs_hmps[0]; |
727 | if (hmp == NULL) | |
728 | return (EINVAL); | |
729 | ||
a7720be7 MD |
730 | hammer2_vfs_sync(ip->pmp->mp, MNT_WAIT); |
731 | ||
c603b86b | 732 | hammer2_trans_init(ip->pmp, HAMMER2_TRANS_ISFLUSH); |
e2163f5b | 733 | mtid = hammer2_trans_sub(ip->pmp); |
b7add675 | 734 | hammer2_inode_lock(ip, 0); |
01d71aa5 MD |
735 | |
736 | chain = hammer2_inode_chain(ip, 0, HAMMER2_RESOLVE_ALWAYS); | |
e2163f5b | 737 | error = hammer2_chain_snapshot(chain, pfs, mtid); |
01d71aa5 MD |
738 | hammer2_chain_unlock(chain); |
739 | hammer2_chain_drop(chain); | |
740 | ||
b7add675 | 741 | hammer2_inode_unlock(ip); |
c603b86b | 742 | hammer2_trans_done(ip->pmp); |
0dea3156 | 743 | |
ae183399 MD |
744 | return (error); |
745 | } | |
344d4f82 MD |
746 | |
747 | /* | |
b7add675 | 748 | * Retrieve the raw inode structure, non-inclusive of node-specific data. |
344d4f82 MD |
749 | */ |
750 | static int | |
751 | hammer2_ioctl_inode_get(hammer2_inode_t *ip, void *data) | |
752 | { | |
6a5f4fe6 | 753 | hammer2_ioc_inode_t *ino; |
01d71aa5 | 754 | hammer2_chain_t *chain; |
b93cc2e0 | 755 | int error; |
01d71aa5 | 756 | int i; |
344d4f82 | 757 | |
6a5f4fe6 | 758 | ino = data; |
01d71aa5 | 759 | error = 0; |
6a5f4fe6 | 760 | |
b7add675 | 761 | hammer2_inode_lock(ip, HAMMER2_RESOLVE_SHARED); |
01d71aa5 MD |
762 | ino->data_count = 0; |
763 | ino->inode_count = 0; | |
764 | for (i = 0; i < ip->cluster.nchains; ++i) { | |
765 | if ((chain = ip->cluster.array[i].chain) != NULL) { | |
766 | if (ino->data_count < chain->bref.data_count) | |
767 | ino->data_count = chain->bref.data_count; | |
768 | if (ino->inode_count < chain->bref.inode_count) | |
769 | ino->inode_count = chain->bref.inode_count; | |
770 | } | |
b93cc2e0 | 771 | } |
b7add675 MD |
772 | bzero(&ino->ip_data, sizeof(ino->ip_data)); |
773 | ino->ip_data.meta = ip->meta; | |
774 | ino->kdata = ip; | |
775 | hammer2_inode_unlock(ip); | |
0dea3156 | 776 | |
b93cc2e0 | 777 | return error; |
344d4f82 MD |
778 | } |
779 | ||
f481450f MD |
780 | /* |
781 | * Set various parameters in an inode which cannot be set through | |
782 | * normal filesystem VNOPS. | |
783 | */ | |
344d4f82 MD |
784 | static int |
785 | hammer2_ioctl_inode_set(hammer2_inode_t *ip, void *data) | |
786 | { | |
787 | hammer2_ioc_inode_t *ino = data; | |
f481450f | 788 | int error = 0; |
344d4f82 | 789 | |
c603b86b | 790 | hammer2_trans_init(ip->pmp, 0); |
b7add675 MD |
791 | hammer2_inode_lock(ip, 0); |
792 | ||
793 | if ((ino->flags & HAMMER2IOC_INODE_FLAG_CHECK) && | |
794 | ip->meta.check_algo != ino->ip_data.meta.check_algo) { | |
795 | hammer2_inode_modify(ip); | |
796 | ip->meta.check_algo = ino->ip_data.meta.check_algo; | |
e07becf8 | 797 | } |
b7add675 MD |
798 | if ((ino->flags & HAMMER2IOC_INODE_FLAG_COMP) && |
799 | ip->meta.comp_algo != ino->ip_data.meta.comp_algo) { | |
800 | hammer2_inode_modify(ip); | |
801 | ip->meta.comp_algo = ino->ip_data.meta.comp_algo; | |
f481450f | 802 | } |
355d67fc MD |
803 | ino->kdata = ip; |
804 | ||
f481450f | 805 | /* Ignore these flags for now...*/ |
b7add675 MD |
806 | if ((ino->flags & HAMMER2IOC_INODE_FLAG_IQUOTA) && |
807 | ip->meta.inode_quota != ino->ip_data.meta.inode_quota) { | |
808 | hammer2_inode_modify(ip); | |
809 | ip->meta.inode_quota = ino->ip_data.meta.inode_quota; | |
344d4f82 | 810 | } |
b7add675 MD |
811 | if ((ino->flags & HAMMER2IOC_INODE_FLAG_DQUOTA) && |
812 | ip->meta.data_quota != ino->ip_data.meta.data_quota) { | |
813 | hammer2_inode_modify(ip); | |
814 | ip->meta.data_quota = ino->ip_data.meta.data_quota; | |
344d4f82 | 815 | } |
b7add675 MD |
816 | if ((ino->flags & HAMMER2IOC_INODE_FLAG_COPIES) && |
817 | ip->meta.ncopies != ino->ip_data.meta.ncopies) { | |
818 | hammer2_inode_modify(ip); | |
819 | ip->meta.ncopies = ino->ip_data.meta.ncopies; | |
344d4f82 | 820 | } |
b7add675 | 821 | hammer2_inode_unlock(ip); |
c603b86b | 822 | hammer2_trans_done(ip->pmp); |
0dea3156 | 823 | |
344d4f82 MD |
824 | return (error); |
825 | } | |
03188ed8 MD |
826 | |
827 | static | |
828 | int | |
829 | hammer2_ioctl_debug_dump(hammer2_inode_t *ip) | |
830 | { | |
831 | hammer2_chain_t *chain; | |
832 | int count = 1000; | |
833 | int i; | |
834 | ||
835 | for (i = 0; i < ip->cluster.nchains; ++i) { | |
4b7e61e0 | 836 | chain = ip->cluster.array[i].chain; |
03188ed8 MD |
837 | if (chain == NULL) |
838 | continue; | |
839 | hammer2_dump_chain(chain, 0, &count, 'i'); | |
840 | } | |
841 | return 0; | |
842 | } | |
3148f677 | 843 | |
21a90458 MD |
844 | /* |
845 | * Executes one flush/free pass per call. If trying to recover | |
846 | * data we just freed up a moment ago it can take up to six passes | |
847 | * to fully free the blocks. Note that passes occur automatically based | |
848 | * on free space as the storage fills up, but manual passes may be needed | |
849 | * if storage becomes almost completely full. | |
850 | */ | |
3148f677 MD |
851 | static |
852 | int | |
853 | hammer2_ioctl_bulkfree_scan(hammer2_inode_t *ip, void *data) | |
854 | { | |
855 | hammer2_ioc_bulkfree_t *bfi = data; | |
01d71aa5 | 856 | hammer2_dev_t *hmp; |
3148f677 MD |
857 | int error; |
858 | ||
01d71aa5 MD |
859 | hmp = ip->pmp->pfs_hmps[0]; |
860 | if (hmp == NULL) | |
861 | return (EINVAL); | |
862 | ||
3148f677 MD |
863 | error = hammer2_bulkfree_pass(hmp, bfi); |
864 | ||
865 | return error; | |
866 | } |