source: mainline/uspace/srv/volsrv/volume.c@ 54593f3

ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 54593f3 was 9e45a41, checked in by Jiri Svoboda <jiri@…>, 6 years ago

Make volume server less chatty

  • Property mode set to 100644
File size: 14.1 KB
RevLine 
[64ffd83]1/*
2 * Copyright (c) 2018 Jiri Svoboda
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * - Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * - Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * - The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29/** @addtogroup volsrv
30 * @{
31 */
32/**
33 * @file Volume handling
34 * @brief
35 *
36 * Volumes are the file systems (or similar) contained in partitions.
37 * Each vol_volume_t can be considered the configuration entry
38 * for a volume. Each partition has an associated vol_volume_t.
39 *
40 * If there is any non-default configuration to be remembered for a
41 * volume, the vol_volume_t structure is kept around even after the partition
42 * is disassociated from it. Otherwise it is deleted once no longer
43 * referenced.
44 */
45
46#include <adt/list.h>
47#include <errno.h>
48#include <fibril_synch.h>
49#include <io/log.h>
50#include <stdbool.h>
51#include <stdlib.h>
52#include <str.h>
53
54#include "volume.h"
55#include "types/volume.h"
56
57static void vol_volume_delete(vol_volume_t *);
58static void vol_volume_add_locked(vol_volumes_t *, vol_volume_t *);
59static errno_t vol_volume_lookup_ref_locked(vol_volumes_t *, const char *,
60 vol_volume_t **);
[1dcba91]61static errno_t vol_volumes_load(sif_node_t *, vol_volumes_t *);
[64ffd83]62
63/** Allocate new volume structure.
64 *
65 * @return Pointer to new volume structure
66 */
67static vol_volume_t *vol_volume_new(void)
68{
69 vol_volume_t *volume = calloc(1, sizeof(vol_volume_t));
70
71 if (volume == NULL) {
72 log_msg(LOG_DEFAULT, LVL_ERROR, "Failed allocating volume "
73 "structure. Out of memory.");
74 return NULL;
75 }
76
77 volume->label = str_dup("");
78 volume->mountp = str_dup("");
79
80 if (volume->label == NULL || volume->mountp == NULL) {
81 vol_volume_delete(volume);
82 return NULL;
83 }
84
[498ced1]85 refcount_init(&volume->refcnt);
[64ffd83]86 link_initialize(&volume->lvolumes);
87 volume->volumes = NULL;
88
89 return volume;
90}
91
92/** Delete volume structure.
93 *
94 * @param volume Volume structure
95 */
96static void vol_volume_delete(vol_volume_t *volume)
97{
[9e45a41]98 log_msg(LOG_DEFAULT, LVL_DEBUG, "Freeing volume %p", volume);
[64ffd83]99
100 free(volume->label);
101 free(volume->mountp);
102 free(volume);
103}
104
105/** Create list of volumes.
106 *
[1dcba91]107 * @param cfg_path Path to file containing configuration repository in SIF
[64ffd83]108 * @param rvolumes Place to store pointer to list of volumes.
109 * @return EOK on success, ENOMEM if out of memory
110 */
[1dcba91]111errno_t vol_volumes_create(const char *cfg_path,
112 vol_volumes_t **rvolumes)
[64ffd83]113{
114 vol_volumes_t *volumes;
[1dcba91]115 sif_sess_t *repo = NULL;
116 sif_trans_t *trans = NULL;
117 sif_node_t *node;
118 const char *ntype;
119 errno_t rc;
[64ffd83]120
121 volumes = calloc(1, sizeof(vol_volumes_t));
122 if (volumes == NULL)
123 return ENOMEM;
124
125 fibril_mutex_initialize(&volumes->lock);
126 list_initialize(&volumes->volumes);
[63c1dd5]127 volumes->next_id = 1;
[64ffd83]128
[1dcba91]129 /* Try opening existing repository */
130 rc = sif_open(cfg_path, &repo);
131 if (rc != EOK) {
132 /* Failed to open existing, create new repository */
133 rc = sif_create(cfg_path, &repo);
134 if (rc != EOK)
135 goto error;
136
137 rc = sif_trans_begin(repo, &trans);
138 if (rc != EOK)
139 goto error;
140
141 /* Create 'volumes' node. */
142 rc = sif_node_append_child(trans, sif_get_root(repo),
143 "volumes", &volumes->nvolumes);
144 if (rc != EOK)
145 goto error;
146
147 rc = sif_trans_end(trans);
148 if (rc != EOK)
149 goto error;
150
151 trans = NULL;
152 } else {
153 /*
154 * Opened existing repo. Find 'volumes' node, should be
155 * the first child of the root node.
156 */
157 node = sif_node_first_child(sif_get_root(repo));
158
159 /* Verify it's the correct node type */
160 ntype = sif_node_get_type(node);
161 if (str_cmp(ntype, "volumes") != 0) {
162 rc = EIO;
163 goto error;
164 }
165
166 rc = vol_volumes_load(node, volumes);
167 if (rc != EOK)
168 goto error;
169 }
170
171 volumes->repo = repo;
[64ffd83]172 *rvolumes = volumes;
[1dcba91]173
[64ffd83]174 return EOK;
[1dcba91]175error:
176 if (trans != NULL)
177 sif_trans_abort(trans);
178 if (repo != NULL)
179 (void) sif_close(repo);
180 if (volumes != NULL)
181 free(volumes);
182
183 return rc;
[64ffd83]184}
185
186/** Destroy list of volumes.
187 *
188 * @param volumes List of volumes or @c NULL
189 */
190void vol_volumes_destroy(vol_volumes_t *volumes)
191{
192 link_t *link;
193 vol_volume_t *volume;
194
195 if (volumes == NULL)
196 return;
197
198 link = list_first(&volumes->volumes);
199 while (link != NULL) {
200 volume = list_get_instance(link, vol_volume_t, lvolumes);
201
202 list_remove(&volume->lvolumes);
203 vol_volume_delete(volume);
204
205 link = list_first(&volumes->volumes);
206 }
207
[df8eaba]208 (void) sif_close(volumes->repo);
[64ffd83]209 free(volumes);
210}
211
212/** Add new volume structure to list of volumes.
213 *
214 * @param volumes List of volumes
215 * @param volume Volume structure
216 */
217static void vol_volume_add_locked(vol_volumes_t *volumes,
218 vol_volume_t *volume)
219{
220 assert(fibril_mutex_is_locked(&volumes->lock));
[9e45a41]221 log_msg(LOG_DEFAULT, LVL_DEBUG, "vol_volume_add_locked(%p)", volume);
[64ffd83]222
223 volume->volumes = volumes;
224 list_append(&volume->lvolumes, &volumes->volumes);
[63c1dd5]225 volume->id.id = volumes->next_id;
226 ++volumes->next_id;
[64ffd83]227}
228
229/** Look up volume structure with locked volumes lock.
230 *
231 * If a matching existing volume is found, it is returned. Otherwise
232 * a new volume structure is created.
233 *
234 * @param volumes List of volumes
235 * @param label Volume label
236 * @param rvolume Place to store pointer to volume structure (existing or new)
237 *
238 * @return EOK on success, ENOMEM if out of memory
239 */
240static errno_t vol_volume_lookup_ref_locked(vol_volumes_t *volumes,
241 const char *label, vol_volume_t **rvolume)
242{
243 vol_volume_t *volume;
244
245 assert(fibril_mutex_is_locked(&volumes->lock));
246
247 list_foreach(volumes->volumes, lvolumes, vol_volume_t, volume) {
248 if (str_cmp(volume->label, label) == 0 &&
249 str_size(label) > 0) {
250 /* Add reference */
[498ced1]251 refcount_up(&volume->refcnt);
[64ffd83]252 *rvolume = volume;
253 return EOK;
254 }
255 }
256
257 /* No existing volume found. Create a new one. */
258 volume = vol_volume_new();
259 if (volume == NULL)
260 return ENOMEM;
261
[1dcba91]262 free(volume->label);
[64ffd83]263 volume->label = str_dup(label);
[1dcba91]264
265 if (volume->label == NULL) {
266 vol_volume_delete(volume);
267 return ENOMEM;
268 }
269
[64ffd83]270 vol_volume_add_locked(volumes, volume);
271
272 *rvolume = volume;
273 return EOK;
274}
275
276/** Look up volume structure.
277 *
278 * If a matching existing volume is found, it is returned. Otherwise
279 * a new volume structure is created.
280 *
281 * @param volumes List of volumes
282 * @param label Volume label
283 * @param rvolume Place to store pointer to volume structure (existing or new)
284 *
285 * @return EOK on success, ENOMEM if out of memory
286 */
287errno_t vol_volume_lookup_ref(vol_volumes_t *volumes, const char *label,
288 vol_volume_t **rvolume)
289{
290 errno_t rc;
291
292 fibril_mutex_lock(&volumes->lock);
293 rc = vol_volume_lookup_ref_locked(volumes, label, rvolume);
294 fibril_mutex_unlock(&volumes->lock);
295
296 return rc;
297}
298
[63c1dd5]299/** Find volume structure by ID with locked volumes lock.
300 * *
301 * @param volumes List of volumes
302 * @param vid Volume ID
303 * @param rvolume Place to store pointer to volume structure (existing or new)
304 *
305 * @return EOK on success, ENOENT if not found
306 */
307static errno_t vol_volume_find_by_id_ref_locked(vol_volumes_t *volumes,
308 volume_id_t vid, vol_volume_t **rvolume)
309{
310 assert(fibril_mutex_is_locked(&volumes->lock));
311
312 list_foreach(volumes->volumes, lvolumes, vol_volume_t, volume) {
313 log_msg(LOG_DEFAULT, LVL_DEBUG2,
314 "vol_volume_find_by_id_ref_locked(%zu==%zu)?",
315 volume->id.id, vid.id);
316 if (volume->id.id == vid.id) {
317 log_msg(LOG_DEFAULT, LVL_DEBUG2,
318 "vol_volume_find_by_id_ref_locked: found");
319 /* Add reference */
320 refcount_up(&volume->refcnt);
321 *rvolume = volume;
322 return EOK;
323 }
324 }
325
326 log_msg(LOG_DEFAULT, LVL_DEBUG2,
327 "vol_volume_find_by_id_ref_locked: not found");
328 return ENOENT;
329}
330
331/** Find volume by ID.
332 *
333 * @param volumes Volumes
334 * @param vid Volume ID
335 * @param rvolume Place to store pointer to volume, with reference count
336 * increased.
337 * @return EOK on success or an error code
338 */
339errno_t vol_volume_find_by_id_ref(vol_volumes_t *volumes, volume_id_t vid,
340 vol_volume_t **rvolume)
341{
342 errno_t rc;
343
344 fibril_mutex_lock(&volumes->lock);
345 rc = vol_volume_find_by_id_ref_locked(volumes, vid, rvolume);
346 fibril_mutex_unlock(&volumes->lock);
347
348 return rc;
349}
350
[64ffd83]351/** Determine if volume has non-default settings that need to persist.
352 *
353 * @param volume Volume
354 * @return @c true iff volume has settings that need to persist
355 */
356static bool vol_volume_is_persist(vol_volume_t *volume)
357{
358 return str_size(volume->mountp) > 0;
359}
360
361/** Delete reference to volume.
362 *
363 * @param volume Volume
364 */
365void vol_volume_del_ref(vol_volume_t *volume)
366{
[498ced1]367 if (refcount_down(&volume->refcnt)) {
[64ffd83]368 /* No more references. Check if volume is persistent. */
[0a201454]369 list_remove(&volume->lvolumes);
370 vol_volume_delete(volume);
[64ffd83]371 }
372}
373
374/** Set volume mount point.
375 *
376 * @param volume Volume
377 * @param mountp Mount point
378 *
379 * @return EOK on success or error code
380 */
381errno_t vol_volume_set_mountp(vol_volume_t *volume, const char *mountp)
382{
383 char *mp;
[1dcba91]384 char *old_mp;
385 errno_t rc;
386 sif_trans_t *trans = NULL;
387 sif_node_t *nvolume;
[64ffd83]388
389 mp = str_dup(mountp);
390 if (mp == NULL)
391 return ENOMEM;
392
[1dcba91]393 old_mp = volume->mountp;
[64ffd83]394 volume->mountp = mp;
395
[1dcba91]396 if (vol_volume_is_persist(volume)) {
397 /* Volume is now persistent */
398 if (volume->nvolume == NULL) {
[0a201454]399 /* Prevent volume from being freed */
400 refcount_up(&volume->refcnt);
401
[1dcba91]402 /* Create volume node */
403 rc = sif_trans_begin(volume->volumes->repo, &trans);
404 if (rc != EOK)
405 goto error;
406
407 rc = sif_node_append_child(trans,
408 volume->volumes->nvolumes, "volume", &nvolume);
409 if (rc != EOK)
410 goto error;
411
412 rc = sif_node_set_attr(trans, nvolume, "label",
413 volume->label);
414 if (rc != EOK)
415 goto error;
416
417 rc = sif_node_set_attr(trans, nvolume, "mountp",
418 volume->mountp);
419 if (rc != EOK)
420 goto error;
421
422 rc = sif_trans_end(trans);
423 if (rc != EOK)
424 goto error;
425
426 trans = NULL;
427 volume->nvolume = nvolume;
428 } else {
[0a201454]429 /* Allow volume to be freed */
430 vol_volume_del_ref(volume);
431
[1dcba91]432 /* Update volume node */
433 rc = sif_trans_begin(volume->volumes->repo, &trans);
434 if (rc != EOK)
435 goto error;
436
437 rc = sif_node_set_attr(trans, volume->nvolume,
438 "mountp", volume->mountp);
439 if (rc != EOK)
440 goto error;
441
442 rc = sif_trans_end(trans);
443 if (rc != EOK)
444 goto error;
445
446 trans = NULL;
447 }
448 } else {
449 /* Volume is now non-persistent */
450 if (volume->nvolume != NULL) {
451 /* Delete volume node */
452 rc = sif_trans_begin(volume->volumes->repo, &trans);
453 if (rc != EOK)
454 goto error;
455
456 sif_node_destroy(trans, volume->nvolume);
457
458 rc = sif_trans_end(trans);
459 if (rc != EOK)
460 goto error;
461
462 volume->nvolume = NULL;
463 }
464 }
465
466 free(old_mp);
[64ffd83]467 return EOK;
[1dcba91]468error:
469 free(mp);
470 volume->mountp = old_mp;
471
472 if (trans != NULL)
473 sif_trans_abort(trans);
474 return rc;
475}
476
[63c1dd5]477/** Get list of volume IDs.
478 *
479 * Get the list of IDs of all persistent volumes (volume configuration
480 * entries).
481 *
482 * @param volumes Volumes
483 * @param id_buf Buffer to hold the IDs
484 * @param buf_size Buffer size in bytes
485 * @param act_size Place to store actual number bytes needed
486 * @return EOK on success or an error code
487 */
488errno_t vol_get_ids(vol_volumes_t *volumes, volume_id_t *id_buf,
489 size_t buf_size, size_t *act_size)
490{
491 size_t act_cnt;
492 size_t buf_cnt;
493
494 fibril_mutex_lock(&volumes->lock);
495
496 buf_cnt = buf_size / sizeof(volume_id_t);
497
498 act_cnt = 0;
499 list_foreach(volumes->volumes, lvolumes, vol_volume_t, volume) {
500 if (vol_volume_is_persist(volume))
501 ++act_cnt;
502 }
503 *act_size = act_cnt * sizeof(volume_id_t);
504
505 if (buf_size % sizeof(volume_id_t) != 0) {
506 fibril_mutex_unlock(&volumes->lock);
507 return EINVAL;
508 }
509
510 size_t pos = 0;
511 list_foreach(volumes->volumes, lvolumes, vol_volume_t, volume) {
512 if (vol_volume_is_persist(volume)) {
513 if (pos < buf_cnt)
514 id_buf[pos].id = volume->id.id;
515 pos++;
516 }
517 }
518
519 fibril_mutex_unlock(&volumes->lock);
520 return EOK;
521}
522
[1dcba91]523/** Load volumes from SIF repository.
524 *
525 * @param nvolumes Volumes node
526 * @param volumes Volumes object
527 *
528 * @return EOK on success or error code
529 */
530static errno_t vol_volumes_load(sif_node_t *nvolumes, vol_volumes_t *volumes)
531{
532 sif_node_t *nvolume;
533 vol_volume_t *volume = NULL;
534 const char *label;
535 const char *mountp;
536 errno_t rc;
537
538 volumes->nvolumes = nvolumes;
539
540 nvolume = sif_node_first_child(nvolumes);
541 while (nvolume != NULL) {
542 if (str_cmp(sif_node_get_type(nvolume), "volume") != 0) {
543 rc = EIO;
544 goto error;
545 }
546
547 volume = vol_volume_new();
548 if (volume == NULL) {
549 rc = ENOMEM;
550 goto error;
551 }
552
553 label = sif_node_get_attr(nvolume, "label");
554 mountp = sif_node_get_attr(nvolume, "mountp");
555
556 if (label == NULL || mountp == NULL) {
557 rc = EIO;
558 goto error;
559 }
560
561 free(volume->label);
562 free(volume->mountp);
563
564 volume->label = str_dup(label);
565 volume->mountp = str_dup(mountp);
566
567 volume->nvolume = nvolume;
568 fibril_mutex_lock(&volumes->lock);
569 vol_volume_add_locked(volumes, volume);
570 fibril_mutex_unlock(&volumes->lock);
571 nvolume = sif_node_next_child(nvolume);
572 }
573
574 return EOK;
575error:
576 if (volume != NULL)
577 vol_volume_delete(volume);
578 return rc;
[64ffd83]579}
580
[63c1dd5]581/** Get volume information.
582 *
583 * @param volume Volume
584 * @param vinfo Volume information structure to safe info to
585 * @return EOK on success or an error code
586 */
587errno_t vol_volume_get_info(vol_volume_t *volume, vol_info_t *vinfo)
588{
589 vinfo->id = volume->id;
590 str_cpy(vinfo->label, sizeof(vinfo->label), volume->label);
591 str_cpy(vinfo->path, sizeof(vinfo->path), volume->mountp);
592 return EOK;
593}
594
[64ffd83]595/** @}
596 */
Note: See TracBrowser for help on using the repository browser.