source: mainline/uspace/srv/volsrv/part.c@ 7a6065c

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 7a6065c was 9c2c7d2, checked in by Jiri Svoboda <jiri@…>, 8 years ago

Fdisk should be able to set volume label for newly created partitions.

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