kernel - Add cluster_readcb()
[dragonfly.git] / sys / vfs / hammer2 / hammer2_ioctl.c
CommitLineData
2910a90c 1/*
0dea3156 2 * Copyright (c) 2011-2013 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 45static int hammer2_ioctl_version_get(hammer2_inode_t *ip, void *data);
1a34728c
MD
46static int hammer2_ioctl_recluster(hammer2_inode_t *ip, void *data);
47static int hammer2_ioctl_remote_scan(hammer2_inode_t *ip, void *data);
ae183399
MD
48static int hammer2_ioctl_remote_add(hammer2_inode_t *ip, void *data);
49static int hammer2_ioctl_remote_del(hammer2_inode_t *ip, void *data);
50static int hammer2_ioctl_remote_rep(hammer2_inode_t *ip, void *data);
51static int hammer2_ioctl_socket_get(hammer2_inode_t *ip, void *data);
52static int hammer2_ioctl_socket_set(hammer2_inode_t *ip, void *data);
53static int hammer2_ioctl_pfs_get(hammer2_inode_t *ip, void *data);
458ecb1b 54static int hammer2_ioctl_pfs_lookup(hammer2_inode_t *ip, void *data);
ae183399 55static int hammer2_ioctl_pfs_create(hammer2_inode_t *ip, void *data);
a864c5d9 56static int hammer2_ioctl_pfs_snapshot(hammer2_inode_t *ip, void *data);
ae183399 57static int hammer2_ioctl_pfs_delete(hammer2_inode_t *ip, void *data);
344d4f82
MD
58static int hammer2_ioctl_inode_get(hammer2_inode_t *ip, void *data);
59static int hammer2_ioctl_inode_set(hammer2_inode_t *ip, void *data);
2910a90c
MD
60
61int
62hammer2_ioctl(hammer2_inode_t *ip, u_long com, void *data, int fflag,
63 struct ucred *cred)
64{
65 int error;
66
67 /*
68 * Standard root cred checks, will be selectively ignored below
69 * for ioctls that do not require root creds.
70 */
71 error = priv_check_cred(cred, PRIV_HAMMER_IOCTL, 0);
72
73 switch(com) {
ae183399
MD
74 case HAMMER2IOC_VERSION_GET:
75 error = hammer2_ioctl_version_get(ip, data);
2910a90c 76 break;
1a34728c 77 case HAMMER2IOC_RECLUSTER:
2910a90c 78 if (error == 0)
1a34728c
MD
79 error = hammer2_ioctl_recluster(ip, data);
80 break;
81 case HAMMER2IOC_REMOTE_SCAN:
82 if (error == 0)
83 error = hammer2_ioctl_remote_scan(ip, data);
2910a90c 84 break;
ae183399 85 case HAMMER2IOC_REMOTE_ADD:
2910a90c 86 if (error == 0)
ae183399 87 error = hammer2_ioctl_remote_add(ip, data);
2910a90c 88 break;
ae183399 89 case HAMMER2IOC_REMOTE_DEL:
2910a90c 90 if (error == 0)
ae183399 91 error = hammer2_ioctl_remote_del(ip, data);
2910a90c 92 break;
ae183399 93 case HAMMER2IOC_REMOTE_REP:
2910a90c 94 if (error == 0)
ae183399 95 error = hammer2_ioctl_remote_rep(ip, data);
2910a90c 96 break;
ae183399 97 case HAMMER2IOC_SOCKET_GET:
2910a90c 98 if (error == 0)
ae183399 99 error = hammer2_ioctl_socket_get(ip, data);
2910a90c 100 break;
ae183399
MD
101 case HAMMER2IOC_SOCKET_SET:
102 if (error == 0)
103 error = hammer2_ioctl_socket_set(ip, data);
104 break;
105 case HAMMER2IOC_PFS_GET:
2910a90c 106 if (error == 0)
ae183399
MD
107 error = hammer2_ioctl_pfs_get(ip, data);
108 break;
458ecb1b
MD
109 case HAMMER2IOC_PFS_LOOKUP:
110 if (error == 0)
111 error = hammer2_ioctl_pfs_lookup(ip, data);
112 break;
ae183399
MD
113 case HAMMER2IOC_PFS_CREATE:
114 if (error == 0)
115 error = hammer2_ioctl_pfs_create(ip, data);
116 break;
117 case HAMMER2IOC_PFS_DELETE:
118 if (error == 0)
119 error = hammer2_ioctl_pfs_delete(ip, data);
2910a90c 120 break;
a864c5d9
MD
121 case HAMMER2IOC_PFS_SNAPSHOT:
122 if (error == 0)
123 error = hammer2_ioctl_pfs_snapshot(ip, data);
124 break;
344d4f82
MD
125 case HAMMER2IOC_INODE_GET:
126 error = hammer2_ioctl_inode_get(ip, data);
127 break;
128 case HAMMER2IOC_INODE_SET:
129 if (error == 0)
130 error = hammer2_ioctl_inode_set(ip, data);
131 break;
2910a90c
MD
132 default:
133 error = EOPNOTSUPP;
134 break;
135 }
136 return (error);
137}
138
139/*
140 * Retrieve version and basic info
141 */
142static int
ae183399 143hammer2_ioctl_version_get(hammer2_inode_t *ip, void *data)
2910a90c
MD
144{
145 hammer2_mount_t *hmp = ip->hmp;
146 hammer2_ioc_version_t *version = data;
147
148 version->version = hmp->voldata.version;
149 return 0;
150}
151
1a34728c
MD
152static int
153hammer2_ioctl_recluster(hammer2_inode_t *ip, void *data)
154{
155 hammer2_ioc_recluster_t *recl = data;
156 struct file *fp;
157
158 fp = holdfp(curproc->p_fd, recl->fd, -1);
159 if (fp) {
160 kprintf("reconnect to cluster\n");
161 hammer2_cluster_reconnect(ip->pmp, fp);
162 return 0;
163 } else {
164 return EINVAL;
165 }
166}
167
2910a90c
MD
168/*
169 * Retrieve information about a remote
170 */
171static int
1a34728c 172hammer2_ioctl_remote_scan(hammer2_inode_t *ip, void *data)
2910a90c
MD
173{
174 hammer2_mount_t *hmp = ip->hmp;
175 hammer2_ioc_remote_t *remote = data;
176 int copyid = remote->copyid;
177
178 if (copyid < 0 || copyid >= HAMMER2_COPYID_COUNT)
179 return (EINVAL);
180
181 hammer2_voldata_lock(hmp);
182 remote->copy1 = hmp->voldata.copyinfo[copyid];
0dea3156 183 hammer2_voldata_unlock(hmp, 0);
2910a90c
MD
184
185 /*
186 * Adjust nextid (GET only)
187 */
188 while (++copyid < HAMMER2_COPYID_COUNT &&
189 hmp->voldata.copyinfo[copyid].copyid == 0) {
1a34728c 190 ;
2910a90c
MD
191 }
192 if (copyid == HAMMER2_COPYID_COUNT)
193 remote->nextid = -1;
194 else
195 remote->nextid = copyid;
196
197 return(0);
198}
199
200/*
201 * Add new remote entry
202 */
203static int
ae183399 204hammer2_ioctl_remote_add(hammer2_inode_t *ip, void *data)
2910a90c
MD
205{
206 hammer2_mount_t *hmp = ip->hmp;
1a34728c 207 hammer2_pfsmount_t *pmp = ip->pmp;
2910a90c
MD
208 hammer2_ioc_remote_t *remote = data;
209 int copyid = remote->copyid;
210 int error = 0;
211
212 if (copyid >= HAMMER2_COPYID_COUNT)
213 return (EINVAL);
214
215 hammer2_voldata_lock(hmp);
216 if (copyid < 0) {
217 for (copyid = 1; copyid < HAMMER2_COPYID_COUNT; ++copyid) {
218 if (hmp->voldata.copyinfo[copyid].copyid == 0)
219 break;
220 }
221 if (copyid == HAMMER2_COPYID_COUNT) {
222 error = ENOSPC;
223 goto failed;
224 }
225 }
226 hammer2_modify_volume(hmp);
2910a90c
MD
227 remote->copy1.copyid = copyid;
228 hmp->voldata.copyinfo[copyid] = remote->copy1;
1a34728c 229 hammer2_volconf_update(pmp, copyid);
2910a90c 230failed:
0dea3156 231 hammer2_voldata_unlock(hmp, 1);
2910a90c
MD
232 return (error);
233}
234
235/*
236 * Delete existing remote entry
237 */
238static int
ae183399 239hammer2_ioctl_remote_del(hammer2_inode_t *ip, void *data)
2910a90c
MD
240{
241 hammer2_mount_t *hmp = ip->hmp;
1a34728c 242 hammer2_pfsmount_t *pmp = ip->pmp;
2910a90c
MD
243 hammer2_ioc_remote_t *remote = data;
244 int copyid = remote->copyid;
245 int error = 0;
246
247 if (copyid >= HAMMER2_COPYID_COUNT)
248 return (EINVAL);
249 remote->copy1.path[sizeof(remote->copy1.path) - 1] = 0;
250 hammer2_voldata_lock(hmp);
251 if (copyid < 0) {
252 for (copyid = 1; copyid < HAMMER2_COPYID_COUNT; ++copyid) {
253 if (hmp->voldata.copyinfo[copyid].copyid == 0)
254 continue;
255 if (strcmp(remote->copy1.path,
256 hmp->voldata.copyinfo[copyid].path) == 0) {
257 break;
258 }
259 }
260 if (copyid == HAMMER2_COPYID_COUNT) {
261 error = ENOENT;
262 goto failed;
263 }
264 }
265 hammer2_modify_volume(hmp);
266 hmp->voldata.copyinfo[copyid].copyid = 0;
1a34728c 267 hammer2_volconf_update(pmp, copyid);
2910a90c 268failed:
0dea3156 269 hammer2_voldata_unlock(hmp, 1);
2910a90c
MD
270 return (error);
271}
272
273/*
274 * Replace existing remote entry
275 */
276static int
ae183399 277hammer2_ioctl_remote_rep(hammer2_inode_t *ip, void *data)
2910a90c
MD
278{
279 hammer2_mount_t *hmp = ip->hmp;
280 hammer2_ioc_remote_t *remote = data;
281 int copyid = remote->copyid;
282
283 if (copyid < 0 || copyid >= HAMMER2_COPYID_COUNT)
284 return (EINVAL);
285
286 hammer2_voldata_lock(hmp);
1a34728c 287 /*hammer2_volconf_update(pmp, copyid);*/
0dea3156 288 hammer2_voldata_unlock(hmp, 1);
2910a90c
MD
289
290 return(0);
291}
292
293/*
294 * Retrieve communications socket
295 */
296static int
ae183399 297hammer2_ioctl_socket_get(hammer2_inode_t *ip, void *data)
2910a90c
MD
298{
299 return (EOPNOTSUPP);
300}
301
302/*
303 * Set communications socket for connection
304 */
305static int
ae183399 306hammer2_ioctl_socket_set(hammer2_inode_t *ip, void *data)
2910a90c
MD
307{
308 hammer2_mount_t *hmp = ip->hmp;
309 hammer2_ioc_remote_t *remote = data;
310 int copyid = remote->copyid;
311
312 if (copyid < 0 || copyid >= HAMMER2_COPYID_COUNT)
313 return (EINVAL);
314
315 hammer2_voldata_lock(hmp);
0dea3156 316 hammer2_voldata_unlock(hmp, 0);
2910a90c
MD
317
318 return(0);
319}
ae183399
MD
320
321/*
a864c5d9
MD
322 * Used to scan and retrieve PFS information. PFS's are directories under
323 * the super-root.
324 *
325 * To scan PFSs pass name_key=0. The function will scan for the next
326 * PFS and set all fields, as well as set name_next to the next key.
327 * When no PFSs remain, name_next is set to (hammer2_key_t)-1.
328 *
329 * To retrieve the PFS associated with the file descriptor, pass
330 * name_key set to (hammer2_key_t)-1.
ae183399
MD
331 */
332static int
333hammer2_ioctl_pfs_get(hammer2_inode_t *ip, void *data)
334{
476d2aad
MD
335 hammer2_inode_data_t *ipdata;
336 hammer2_mount_t *hmp;
337 hammer2_ioc_pfs_t *pfs;
ae183399
MD
338 hammer2_chain_t *parent;
339 hammer2_chain_t *chain;
a864c5d9 340 hammer2_chain_t *rchain;
476d2aad 341 int error;
ae183399 342
476d2aad
MD
343 error = 0;
344 hmp = ip->hmp;
345 pfs = data;
0dea3156 346 parent = hammer2_chain_lookup_init(hmp->schain, 0);
a864c5d9 347 rchain = ip->pmp->rchain;
ae183399
MD
348
349 /*
350 * Search for the first key or specific key. Remember that keys
351 * can be returned in any order.
352 */
353 if (pfs->name_key == 0) {
0dea3156 354 chain = hammer2_chain_lookup(&parent,
ae183399 355 0, (hammer2_key_t)-1, 0);
a864c5d9
MD
356 } else if (pfs->name_key == (hammer2_key_t)-1) {
357 chain = hammer2_chain_lookup(&parent,
358 rchain->data->ipdata.name_key,
359 rchain->data->ipdata.name_key,
360 0);
ae183399 361 } else {
0dea3156 362 chain = hammer2_chain_lookup(&parent,
ae183399
MD
363 pfs->name_key, pfs->name_key, 0);
364 }
365 while (chain && chain->bref.type != HAMMER2_BREF_TYPE_INODE) {
0dea3156
MD
366 chain = hammer2_chain_next(&parent, chain,
367 0, (hammer2_key_t)-1, 0);
ae183399
MD
368 }
369 if (chain) {
370 /*
371 * Load the data being returned by the ioctl.
372 */
476d2aad
MD
373 ipdata = &chain->data->ipdata;
374 pfs->name_key = ipdata->name_key;
375 pfs->pfs_type = ipdata->pfs_type;
376 pfs->pfs_clid = ipdata->pfs_clid;
377 pfs->pfs_fsid = ipdata->pfs_fsid;
378 KKASSERT(ipdata->name_len < sizeof(pfs->name));
379 bcopy(ipdata->filename, pfs->name, ipdata->name_len);
380 pfs->name[ipdata->name_len] = 0;
381 ipdata = NULL; /* safety */
ae183399
MD
382
383 /*
384 * Calculate the next field
385 */
386 do {
0dea3156
MD
387 chain = hammer2_chain_next(&parent, chain,
388 0, (hammer2_key_t)-1, 0);
ae183399
MD
389 } while (chain && chain->bref.type != HAMMER2_BREF_TYPE_INODE);
390 if (chain) {
476d2aad 391 pfs->name_next = chain->data->ipdata.name_key;
0dea3156 392 hammer2_chain_unlock(chain);
ae183399
MD
393 } else {
394 pfs->name_next = (hammer2_key_t)-1;
395 }
396 } else {
397 pfs->name_next = (hammer2_key_t)-1;
398 error = ENOENT;
399 }
0dea3156
MD
400 hammer2_chain_lookup_done(parent);
401
ae183399
MD
402 return (error);
403}
404
458ecb1b
MD
405/*
406 * Find a specific PFS by name
407 */
408static int
409hammer2_ioctl_pfs_lookup(hammer2_inode_t *ip, void *data)
410{
476d2aad
MD
411 hammer2_inode_data_t *ipdata;
412 hammer2_mount_t *hmp;
413 hammer2_ioc_pfs_t *pfs;
458ecb1b
MD
414 hammer2_chain_t *parent;
415 hammer2_chain_t *chain;
458ecb1b 416 hammer2_key_t lhc;
476d2aad 417 int error;
458ecb1b
MD
418 size_t len;
419
476d2aad
MD
420 error = 0;
421 hmp = ip->hmp;
422 pfs = data;
0dea3156 423 parent = hammer2_chain_lookup_init(hmp->schain, HAMMER2_LOOKUP_SHARED);
458ecb1b
MD
424
425 pfs->name[sizeof(pfs->name) - 1] = 0;
426 len = strlen(pfs->name);
427 lhc = hammer2_dirhash(pfs->name, len);
428
0dea3156 429 chain = hammer2_chain_lookup(&parent,
458ecb1b
MD
430 lhc, lhc + HAMMER2_DIRHASH_LOMASK,
431 HAMMER2_LOOKUP_SHARED);
432 while (chain) {
433 if (chain->bref.type == HAMMER2_BREF_TYPE_INODE &&
458ecb1b
MD
434 len == chain->data->ipdata.name_len &&
435 bcmp(pfs->name, chain->data->ipdata.filename, len) == 0) {
436 break;
437 }
0dea3156 438 chain = hammer2_chain_next(&parent, chain,
458ecb1b
MD
439 lhc, lhc + HAMMER2_DIRHASH_LOMASK,
440 HAMMER2_LOOKUP_SHARED);
441 }
442
443 /*
444 * Load the data being returned by the ioctl.
445 */
446 if (chain) {
476d2aad
MD
447 ipdata = &chain->data->ipdata;
448 pfs->name_key = ipdata->name_key;
449 pfs->pfs_type = ipdata->pfs_type;
450 pfs->pfs_clid = ipdata->pfs_clid;
451 pfs->pfs_fsid = ipdata->pfs_fsid;
452 ipdata = NULL;
458ecb1b 453
0dea3156 454 hammer2_chain_unlock(chain);
458ecb1b
MD
455 } else {
456 error = ENOENT;
457 }
0dea3156 458 hammer2_chain_lookup_done(parent);
458ecb1b
MD
459 return (error);
460}
461
ae183399
MD
462/*
463 * Create a new PFS under the super-root
464 */
465static int
466hammer2_ioctl_pfs_create(hammer2_inode_t *ip, void *data)
467{
476d2aad
MD
468 hammer2_inode_data_t *nipdata;
469 hammer2_mount_t *hmp;
470 hammer2_ioc_pfs_t *pfs;
471 hammer2_inode_t *nip;
9596b8c4 472 hammer2_chain_t *nchain;
0dea3156 473 hammer2_trans_t trans;
ae183399
MD
474 int error;
475
476d2aad
MD
476 hmp = ip->hmp;
477 pfs = data;
478 nip = NULL;
479
a864c5d9
MD
480 if (pfs->name[0] == 0)
481 return(EINVAL);
ae183399 482 pfs->name[sizeof(pfs->name) - 1] = 0; /* ensure 0-termination */
10252dc7 483
1a7cfe5a 484 hammer2_trans_init(&trans, hmp, ip, 0);
0dea3156 485 nip = hammer2_inode_create(&trans, hmp->sroot, NULL, NULL,
ae183399 486 pfs->name, strlen(pfs->name),
9596b8c4 487 &nchain, &error);
ae183399 488 if (error == 0) {
9596b8c4 489 nipdata = hammer2_chain_modify_ip(&trans, nip, &nchain,
4a59bd3e 490 HAMMER2_MODIFY_ASSERTNOCOPY);
476d2aad
MD
491 nipdata->pfs_type = pfs->pfs_type;
492 nipdata->pfs_clid = pfs->pfs_clid;
493 nipdata->pfs_fsid = pfs->pfs_fsid;
9596b8c4 494 hammer2_inode_unlock_ex(nip, nchain);
ae183399 495 }
0dea3156 496 hammer2_trans_done(&trans);
ae183399
MD
497 return (error);
498}
499
500/*
501 * Destroy an existing PFS under the super-root
502 */
503static int
504hammer2_ioctl_pfs_delete(hammer2_inode_t *ip, void *data)
505{
506 hammer2_mount_t *hmp = ip->hmp;
507 hammer2_ioc_pfs_t *pfs = data;
0dea3156 508 hammer2_trans_t trans;
ae183399
MD
509 int error;
510
1a7cfe5a 511 hammer2_trans_init(&trans, hmp, ip, 0);
0dea3156 512 error = hammer2_unlink_file(&trans, hmp->sroot,
9797e933 513 pfs->name, strlen(pfs->name),
a864c5d9
MD
514 2, NULL);
515 hammer2_trans_done(&trans);
516
517 return (error);
518}
519
520static int
521hammer2_ioctl_pfs_snapshot(hammer2_inode_t *ip, void *data)
522{
523 hammer2_mount_t *hmp = ip->hmp;
524 hammer2_ioc_pfs_t *pfs = data;
525 hammer2_trans_t trans;
9596b8c4 526 hammer2_chain_t *parent;
a864c5d9
MD
527 int error;
528
529 if (pfs->name[0] == 0)
530 return(EINVAL);
531 if (pfs->name[sizeof(pfs->name)-1] != 0)
532 return(EINVAL);
533
1a7cfe5a 534 hammer2_trans_init(&trans, hmp, ip, 0);
9596b8c4 535 parent = hammer2_inode_lock_ex(ip);
a864c5d9 536 error = hammer2_chain_snapshot(&trans, ip, pfs);
9596b8c4 537 hammer2_inode_unlock_ex(ip, parent);
0dea3156
MD
538 hammer2_trans_done(&trans);
539
ae183399
MD
540 return (error);
541}
344d4f82
MD
542
543/*
544 * Retrieve the raw inode structure
545 */
546static int
547hammer2_ioctl_inode_get(hammer2_inode_t *ip, void *data)
548{
549 hammer2_ioc_inode_t *ino = data;
9596b8c4 550 hammer2_chain_t *parent;
344d4f82 551
9596b8c4 552 parent = hammer2_inode_lock_sh(ip);
0dea3156 553 ino->ip_data = ip->chain->data->ipdata;
26b047fa 554 ino->kdata = ip;
9596b8c4 555 hammer2_inode_unlock_sh(ip, parent);
0dea3156 556
344d4f82
MD
557 return (0);
558}
559
560static int
561hammer2_ioctl_inode_set(hammer2_inode_t *ip, void *data)
562{
563 hammer2_ioc_inode_t *ino = data;
9596b8c4 564 hammer2_chain_t *parent;
344d4f82
MD
565 int error = EINVAL;
566
9596b8c4 567 parent = hammer2_inode_lock_ex(ip);
344d4f82
MD
568 if (ino->flags & HAMMER2IOC_INODE_FLAG_IQUOTA) {
569 }
570 if (ino->flags & HAMMER2IOC_INODE_FLAG_DQUOTA) {
571 }
572 if (ino->flags & HAMMER2IOC_INODE_FLAG_COPIES) {
573 }
9596b8c4 574 hammer2_inode_unlock_ex(ip, parent);
0dea3156 575
344d4f82
MD
576 return (error);
577}