source: mainline/uspace/srv/volsrv/part.c@ 36f0738

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 36f0738 was dd8ab1c, checked in by Jiří Zárevúcky <zarevucky.jiri@…>, 8 years ago

More str_error() additions.

  • Property mode set to 100644
File size: 8.2 KB
Line 
1/*
2 * Copyright (c) 2015 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 Partition handling
34 * @brief
35 */
36
37#include <stdbool.h>
38#include <errno.h>
39#include <str_error.h>
40#include <fibril_synch.h>
41#include <io/log.h>
42#include <loc.h>
43#include <stdlib.h>
44#include <str.h>
45#include <vfs/vfs.h>
46
47#include "empty.h"
48#include "mkfs.h"
49#include "part.h"
50#include "types/part.h"
51
52static int vol_part_add_locked(service_id_t);
53static LIST_INITIALIZE(vol_parts); /* of vol_part_t */
54static FIBRIL_MUTEX_INITIALIZE(vol_parts_lock);
55
56struct fsname_type {
57 const char *name;
58 vol_fstype_t fstype;
59};
60
61static struct fsname_type fstab[] = {
62 { "ext4fs", fs_ext4 },
63 { "cdfs", fs_cdfs },
64 { "exfat", fs_exfat },
65 { "fat", fs_fat },
66 { "mfs", fs_minix },
67 { NULL, 0 }
68};
69
70/** Check for new partitions */
71static int vol_part_check_new(void)
72{
73 bool already_known;
74 category_id_t part_cat;
75 service_id_t *svcs;
76 size_t count, i;
77 int rc;
78
79 fibril_mutex_lock(&vol_parts_lock);
80
81 rc = loc_category_get_id("partition", &part_cat, IPC_FLAG_BLOCKING);
82 if (rc != EOK) {
83 log_msg(LOG_DEFAULT, LVL_ERROR, "Failed resolving category 'partition'.");
84 fibril_mutex_unlock(&vol_parts_lock);
85 return ENOENT;
86 }
87
88 rc = loc_category_get_svcs(part_cat, &svcs, &count);
89 if (rc != EOK) {
90 log_msg(LOG_DEFAULT, LVL_ERROR, "Failed getting list of partition "
91 "devices.");
92 fibril_mutex_unlock(&vol_parts_lock);
93 return EIO;
94 }
95
96 for (i = 0; i < count; i++) {
97 already_known = false;
98
99 list_foreach(vol_parts, lparts, vol_part_t, part) {
100 if (part->svc_id == svcs[i]) {
101 already_known = true;
102 break;
103 }
104 }
105
106 if (!already_known) {
107 log_msg(LOG_DEFAULT, LVL_NOTE, "Found partition '%lu'",
108 (unsigned long) svcs[i]);
109 rc = vol_part_add_locked(svcs[i]);
110 if (rc != EOK) {
111 log_msg(LOG_DEFAULT, LVL_ERROR, "Could not add "
112 "partition.");
113 }
114 }
115 }
116
117 fibril_mutex_unlock(&vol_parts_lock);
118 return EOK;
119}
120
121static vol_part_t *vol_part_new(void)
122{
123 vol_part_t *part = calloc(1, sizeof(vol_part_t));
124
125 if (part == NULL) {
126 log_msg(LOG_DEFAULT, LVL_ERROR, "Failed allocating partition "
127 "structure. Out of memory.");
128 return NULL;
129 }
130
131 link_initialize(&part->lparts);
132 part->pcnt = vpc_empty;
133
134 return part;
135}
136
137static void vol_part_delete(vol_part_t *part)
138{
139 if (part == NULL)
140 return;
141
142 free(part->svc_name);
143 free(part);
144}
145
146static int vol_part_probe(vol_part_t *part)
147{
148 bool empty;
149 vfs_fs_probe_info_t info;
150 struct fsname_type *fst;
151 char *label;
152 int rc;
153
154 log_msg(LOG_DEFAULT, LVL_NOTE, "Probe partition %s", part->svc_name);
155
156 assert(fibril_mutex_is_locked(&vol_parts_lock));
157
158 fst = &fstab[0];
159 while (fst->name != NULL) {
160 rc = vfs_fsprobe(fst->name, part->svc_id, &info);
161 if (rc == EOK)
162 break;
163 ++fst;
164 }
165
166 if (fst->name != NULL) {
167 log_msg(LOG_DEFAULT, LVL_NOTE, "Found %s, label '%s'",
168 fst->name, info.label);
169 label = str_dup(info.label);
170 if (label == NULL) {
171 rc = ENOMEM;
172 goto error;
173 }
174
175 part->pcnt = vpc_fs;
176 part->fstype = fst->fstype;
177 part->label = label;
178 } else {
179 log_msg(LOG_DEFAULT, LVL_NOTE, "Partition does not contain "
180 "a recognized file system.");
181
182 rc = volsrv_part_is_empty(part->svc_id, &empty);
183 if (rc != EOK) {
184 log_msg(LOG_DEFAULT, LVL_ERROR, "Failed determining if "
185 "partition is empty.");
186 rc = EIO;
187 goto error;
188 }
189
190 label = str_dup("");
191 if (label == NULL) {
192 rc = ENOMEM;
193 goto error;
194 }
195
196 part->pcnt = empty ? vpc_empty : vpc_unknown;
197 part->label = label;
198 }
199
200 return EOK;
201
202error:
203 return rc;
204}
205
206static int vol_part_add_locked(service_id_t sid)
207{
208 vol_part_t *part;
209 int rc;
210
211 assert(fibril_mutex_is_locked(&vol_parts_lock));
212
213 /* Check for duplicates */
214 rc = vol_part_find_by_id(sid, &part);
215 if (rc == EOK)
216 return EEXIST;
217
218 log_msg(LOG_DEFAULT, LVL_DEBUG, "vol_part_add_locked()");
219 part = vol_part_new();
220 if (part == NULL)
221 return ENOMEM;
222
223 part->svc_id = sid;
224
225 rc = loc_service_get_name(sid, &part->svc_name);
226 if (rc != EOK) {
227 log_msg(LOG_DEFAULT, LVL_ERROR, "Failed getting service name.");
228 goto error;
229 }
230
231 rc = vol_part_probe(part);
232 if (rc != EOK)
233 goto error;
234
235 list_append(&part->lparts, &vol_parts);
236
237 log_msg(LOG_DEFAULT, LVL_NOTE, "Added partition %zu", part->svc_id);
238
239 return EOK;
240
241error:
242 vol_part_delete(part);
243 return rc;
244}
245
246int vol_part_add(service_id_t sid)
247{
248 int rc;
249
250 fibril_mutex_lock(&vol_parts_lock);
251 rc = vol_part_add_locked(sid);
252 fibril_mutex_unlock(&vol_parts_lock);
253
254 return rc;
255}
256
257static void vol_part_cat_change_cb(void)
258{
259 (void) vol_part_check_new();
260}
261
262int vol_part_init(void)
263{
264 return EOK;
265}
266
267int vol_part_discovery_start(void)
268{
269 int rc;
270
271 rc = loc_register_cat_change_cb(vol_part_cat_change_cb);
272 if (rc != EOK) {
273 log_msg(LOG_DEFAULT, LVL_ERROR, "Failed registering callback "
274 "for partition discovery: %s.", str_error(rc));
275 return rc;
276 }
277
278 return vol_part_check_new();
279}
280
281/** Get list of partitions as array of service IDs. */
282int vol_part_get_ids(service_id_t *id_buf, size_t buf_size, size_t *act_size)
283{
284 size_t act_cnt;
285 size_t buf_cnt;
286
287 fibril_mutex_lock(&vol_parts_lock);
288
289 buf_cnt = buf_size / sizeof(service_id_t);
290
291 act_cnt = list_count(&vol_parts);
292 *act_size = act_cnt * sizeof(service_id_t);
293
294 if (buf_size % sizeof(service_id_t) != 0) {
295 fibril_mutex_unlock(&vol_parts_lock);
296 return EINVAL;
297 }
298
299 size_t pos = 0;
300 list_foreach(vol_parts, lparts, vol_part_t, part) {
301 if (pos < buf_cnt)
302 id_buf[pos] = part->svc_id;
303 pos++;
304 }
305
306 fibril_mutex_unlock(&vol_parts_lock);
307 return EOK;
308}
309
310int vol_part_find_by_id(service_id_t sid, vol_part_t **rpart)
311{
312 list_foreach(vol_parts, lparts, vol_part_t, part) {
313 if (part->svc_id == sid) {
314 *rpart = part;
315 /* XXX Add reference */
316 return EOK;
317 }
318 }
319
320 return ENOENT;
321}
322
323int vol_part_empty_part(vol_part_t *part)
324{
325 int rc;
326
327 log_msg(LOG_DEFAULT, LVL_DEBUG, "vol_part_empty_part()");
328
329 rc = volsrv_part_empty(part->svc_id);
330 if (rc != EOK) {
331 log_msg(LOG_DEFAULT, LVL_DEBUG, "vol_part_empty_part() - failed %s",
332 str_error(rc));
333 return rc;
334 }
335
336 part->pcnt = vpc_empty;
337 return EOK;
338}
339
340int vol_part_mkfs_part(vol_part_t *part, vol_fstype_t fstype,
341 const char *label)
342{
343 int rc;
344
345 log_msg(LOG_DEFAULT, LVL_DEBUG, "vol_part_mkfs_part()");
346
347 fibril_mutex_lock(&vol_parts_lock);
348
349 rc = volsrv_part_mkfs(part->svc_id, fstype, label);
350 if (rc != EOK) {
351 log_msg(LOG_DEFAULT, LVL_DEBUG, "vol_part_mkfs_part() - failed %s",
352 str_error(rc));
353 fibril_mutex_unlock(&vol_parts_lock);
354 return rc;
355 }
356
357 /*
358 * Re-probe the partition to update information. This is needed since
359 * the FS can make conversions of the volume label (e.g. make it
360 * uppercase).
361 */
362 rc = vol_part_probe(part);
363 if (rc != EOK) {
364 fibril_mutex_unlock(&vol_parts_lock);
365 return rc;
366 }
367
368 fibril_mutex_unlock(&vol_parts_lock);
369 return EOK;
370}
371
372int vol_part_get_info(vol_part_t *part, vol_part_info_t *pinfo)
373{
374 pinfo->pcnt = part->pcnt;
375 pinfo->fstype = part->fstype;
376 str_cpy(pinfo->label, sizeof(pinfo->label), part->label);
377 return EOK;
378}
379
380/** @}
381 */
Note: See TracBrowser for help on using the repository browser.