glusterfs

Форк
0
/
stripe-merge.c 
503 строки · 12.5 Кб
1
/*
2
  Copyright (c) 2008-2012 Red Hat, Inc. <http://www.redhat.com>
3
  This file is part of GlusterFS.
4

5
  This file is licensed to you under your choice of the GNU Lesser
6
  General Public License, version 3 or any later version (LGPLv3 or
7
  later), or the GNU General Public License, version 2 (GPLv2), in all
8
  cases as published by the Free Software Foundation.
9
*/
10

11
/*
12
 * stripe-merge.c
13
 *
14
 * This program recovers an original file based on the striped files stored on
15
 * the individual bricks of a striped volume. The file format and stripe
16
 * geometry is validated through the extended attributes stored in the file.
17
 *
18
 * TODO: Support optional xattr recovery (i.e., user xattrs). Perhaps provide a
19
 * 	 command-line flag to toggle this behavior.
20
 */
21

22
#include <stdio.h>
23
#include <sys/types.h>
24
#include <sys/stat.h>
25
#include <fcntl.h>
26
#include <unistd.h>
27
#include <stdlib.h>
28
#include <stdint.h>
29
#include <errno.h>
30
#include <string.h>
31
#include <sys/xattr.h>
32
#include <fnmatch.h>
33

34
#define ATTRNAME_STRIPE_INDEX "trusted.*.stripe-index"
35
#define ATTRNAME_STRIPE_COUNT "trusted.*.stripe-count"
36
#define ATTRNAME_STRIPE_SIZE "trusted.*.stripe-size"
37
#define ATTRNAME_STRIPE_COALESCE "trusted.*.stripe-coalesce"
38

39
#define INVALID_FD -1
40
#define INVALID_MODE UINT32_MAX
41

42
struct file_stripe_info {
43
    int stripe_count;
44
    int stripe_size;
45
    int coalesce;
46
    mode_t mode;
47
    int fd[0];
48
};
49

50
static int
51
close_files(struct file_stripe_info *);
52

53
static struct file_stripe_info *
54
alloc_file_stripe_info(int count)
55
{
56
    int i;
57
    struct file_stripe_info *finfo;
58

59
    finfo = calloc(1, sizeof(struct file_stripe_info) + (sizeof(int) * count));
60
    if (!finfo)
61
        return NULL;
62

63
    for (i = 0; i < count; i++)
64
        finfo->fd[i] = INVALID_FD;
65

66
    finfo->mode = INVALID_MODE;
67
    finfo->coalesce = INVALID_FD;
68

69
    return finfo;
70
}
71

72
/*
73
 * Search for an attribute matching the provided pattern. Return a count for
74
 * the total number of matching entries (including 0). Allocate a buffer for
75
 * the first matching entry found.
76
 */
77
static int
78
get_stripe_attr_name(const char *path, const char *pattern, char **attrname)
79
{
80
    char attrbuf[4096];
81
    char *ptr, *match = NULL;
82
    int len, r, match_count = 0;
83

84
    if (!path || !pattern || !attrname)
85
        return -1;
86

87
    len = listxattr(path, attrbuf, sizeof(attrbuf));
88
    if (len < 0)
89
        return len;
90

91
    ptr = attrbuf;
92
    while (ptr) {
93
        r = fnmatch(pattern, ptr, 0);
94
        if (!r) {
95
            if (!match)
96
                match = ptr;
97
            match_count++;
98
        } else if (r != FNM_NOMATCH) {
99
            return -1;
100
        }
101

102
        len -= strlen(ptr) + 1;
103
        if (len > 0)
104
            ptr += strlen(ptr) + 1;
105
        else
106
            ptr = NULL;
107
    }
108

109
    if (match)
110
        *attrname = strdup(match);
111

112
    return match_count;
113
}
114

115
/*
116
 * Get the integer representation of a named attribute.
117
 */
118
static int
119
get_stripe_attr_val(const char *path, const char *attr, int *val)
120
{
121
    char attrbuf[4096];
122
    int len;
123

124
    if (!path || !attr || !val)
125
        return -1;
126

127
    len = getxattr(path, attr, attrbuf, sizeof(attrbuf));
128
    if (len < 0)
129
        return len;
130

131
    *val = atoi(attrbuf);
132

133
    return 0;
134
}
135

136
/*
137
 * Get an attribute name/value (assumed to be an integer) pair based on a
138
 * specified search pattern. A buffer is allocated for the exact attr name
139
 * returned. Optionally, skip the pattern search if a buffer is provided
140
 * (which should contain an attribute name).
141
 *
142
 * Returns the attribute count or -1 on error. The value parameter is set only
143
 * when a single attribute is found.
144
 */
145
static int
146
get_attr(const char *path, const char *pattern, char **buf, int *val)
147
{
148
    int count = 1;
149

150
    if (!buf)
151
        return -1;
152

153
    if (!*buf) {
154
        count = get_stripe_attr_name(path, pattern, buf);
155
        if (count > 1) {
156
            /* pattern isn't good enough */
157
            fprintf(stderr,
158
                    "ERROR: duplicate attributes found "
159
                    "matching pattern: %s\n",
160
                    pattern);
161
            free(*buf);
162
            *buf = NULL;
163
            return count;
164
        } else if (count < 1) {
165
            return count;
166
        }
167
    }
168

169
    if (get_stripe_attr_val(path, *buf, val) < 0)
170
        return -1;
171

172
    return count;
173
}
174

175
/*
176
 * validate_and_open_files()
177
 *
178
 * Open the provided source files and validate the extended attributes. Verify
179
 * that the geometric attributes are consistent across all of the files and
180
 * print a warning if any files are missing. We proceed without error in the
181
 * latter case to support partial recovery.
182
 */
183
static struct file_stripe_info *
184
validate_and_open_files(char *paths[], int count)
185
{
186
    int i, val, tmp;
187
    struct stat sbuf;
188
    char *stripe_count_attr = NULL;
189
    char *stripe_size_attr = NULL;
190
    char *stripe_index_attr = NULL;
191
    char *stripe_coalesce_attr = NULL;
192
    struct file_stripe_info *finfo = NULL;
193

194
    for (i = 0; i < count; i++) {
195
        if (!paths[i])
196
            goto err;
197

198
        /*
199
         * Check the stripe count first so we can allocate the info
200
         * struct with the appropriate number of fds.
201
         */
202
        if (get_attr(paths[i], ATTRNAME_STRIPE_COUNT, &stripe_count_attr,
203
                     &val) != 1) {
204
            fprintf(stderr, "ERROR: %s: attribute: '%s'\n", paths[i],
205
                    ATTRNAME_STRIPE_COUNT);
206
            goto err;
207
        }
208
        if (!finfo) {
209
            finfo = alloc_file_stripe_info(val);
210
            if (!finfo)
211
                goto err;
212

213
            if (val != count)
214
                fprintf(stderr,
215
                        "WARNING: %s: stripe-count "
216
                        "(%d) != file count (%d). Result may "
217
                        "be incomplete.\n",
218
                        paths[i], val, count);
219

220
            finfo->stripe_count = val;
221
        } else if (val != finfo->stripe_count) {
222
            fprintf(stderr,
223
                    "ERROR %s: invalid stripe count: %d "
224
                    "(expected %d)\n",
225
                    paths[i], val, finfo->stripe_count);
226
            goto err;
227
        }
228

229
        /*
230
         * Get and validate the chunk size.
231
         */
232
        if (get_attr(paths[i], ATTRNAME_STRIPE_SIZE, &stripe_size_attr, &val) !=
233
            1) {
234
            fprintf(stderr, "ERROR: %s: attribute: '%s'\n", paths[i],
235
                    ATTRNAME_STRIPE_SIZE);
236
            goto err;
237
        }
238

239
        if (!finfo->stripe_size) {
240
            finfo->stripe_size = val;
241
        } else if (val != finfo->stripe_size) {
242
            fprintf(stderr,
243
                    "ERROR: %s: invalid stripe size: %d "
244
                    "(expected %d)\n",
245
                    paths[i], val, finfo->stripe_size);
246
            goto err;
247
        }
248

249
        /*
250
         * stripe-coalesce is a backward compatible attribute. If the
251
         * attribute does not exist, assume a value of zero for the
252
         * traditional stripe format.
253
         */
254
        tmp = get_attr(paths[i], ATTRNAME_STRIPE_COALESCE,
255
                       &stripe_coalesce_attr, &val);
256
        if (!tmp) {
257
            val = 0;
258
        } else if (tmp != 1) {
259
            fprintf(stderr, "ERROR: %s: attribute: '%s'\n", paths[i],
260
                    ATTRNAME_STRIPE_COALESCE);
261
            goto err;
262
        }
263

264
        if (finfo->coalesce == INVALID_FD) {
265
            finfo->coalesce = val;
266
        } else if (val != finfo->coalesce) {
267
            fprintf(stderr, "ERROR: %s: invalid coalesce flag\n", paths[i]);
268
            goto err;
269
        }
270

271
        /*
272
         * Get/validate the stripe index and open the file in the
273
         * appropriate fd slot.
274
         */
275
        if (get_attr(paths[i], ATTRNAME_STRIPE_INDEX, &stripe_index_attr,
276
                     &val) != 1) {
277
            fprintf(stderr, "ERROR: %s: attribute: '%s'\n", paths[i],
278
                    ATTRNAME_STRIPE_INDEX);
279
            goto err;
280
        }
281
        if (finfo->fd[val] != INVALID_FD) {
282
            fprintf(stderr,
283
                    "ERROR: %s: duplicate stripe index: "
284
                    "%d\n",
285
                    paths[i], val);
286
            goto err;
287
        }
288

289
        finfo->fd[val] = open(paths[i], O_RDONLY);
290
        if (finfo->fd[val] < 0)
291
            goto err;
292

293
        /*
294
         * Get the creation mode for the file.
295
         */
296
        if (fstat(finfo->fd[val], &sbuf) < 0)
297
            goto err;
298
        if (finfo->mode == INVALID_MODE) {
299
            finfo->mode = sbuf.st_mode;
300
        } else if (sbuf.st_mode != finfo->mode) {
301
            fprintf(stderr, "ERROR: %s: invalid mode\n", paths[i]);
302
            goto err;
303
        }
304
    }
305

306
    free(stripe_count_attr);
307
    free(stripe_size_attr);
308
    free(stripe_index_attr);
309
    free(stripe_coalesce_attr);
310

311
    return finfo;
312
err:
313

314
    free(stripe_count_attr);
315
    free(stripe_size_attr);
316
    free(stripe_index_attr);
317
    free(stripe_coalesce_attr);
318

319
    if (finfo) {
320
        close_files(finfo);
321
        free(finfo);
322
    }
323

324
    return NULL;
325
}
326

327
static int
328
close_files(struct file_stripe_info *finfo)
329
{
330
    int i, ret;
331

332
    if (!finfo)
333
        return -1;
334

335
    for (i = 0; i < finfo->stripe_count; i++) {
336
        if (finfo->fd[i] == INVALID_FD)
337
            continue;
338

339
        ret = close(finfo->fd[i]);
340
        if (ret < 0)
341
            return ret;
342
    }
343

344
    return ret;
345
}
346

347
/*
348
 * Generate the original file using files striped in the coalesced format.
349
 * Data in the striped files is stored at a coalesced offset based on the
350
 * stripe number.
351
 *
352
 * Walk through the finfo fds (which are already ordered) and and iteratively
353
 * copy stripe_size bytes from the source files to the target file. If a source
354
 * file is missing, seek past the associated stripe_size bytes in the target
355
 * file.
356
 */
357
static int
358
generate_file_coalesce(int target, struct file_stripe_info *finfo)
359
{
360
    char *buf;
361
    int ret = 0;
362
    int r, w, i;
363

364
    buf = malloc(finfo->stripe_size);
365
    if (!buf)
366
        return -1;
367

368
    i = 0;
369
    while (1) {
370
        if (finfo->fd[i] == INVALID_FD) {
371
            if (lseek(target, finfo->stripe_size, SEEK_CUR) < 0)
372
                break;
373

374
            i = (i + 1) % finfo->stripe_count;
375
            continue;
376
        }
377

378
        r = read(finfo->fd[i], buf, finfo->stripe_size);
379
        if (r < 0) {
380
            ret = r;
381
            break;
382
        }
383
        if (!r)
384
            break;
385

386
        w = write(target, buf, r);
387
        if (w < 0) {
388
            ret = w;
389
            break;
390
        }
391

392
        i = (i + 1) % finfo->stripe_count;
393
    }
394

395
    free(buf);
396
    return ret;
397
}
398

399
/*
400
 * Generate the original file using files striped with the traditional stripe
401
 * format. Data in the striped files is stored at the equivalent offset from
402
 * the source file.
403
 */
404
static int
405
generate_file_traditional(int target, struct file_stripe_info *finfo)
406
{
407
    int i, j, max_ret, ret;
408
    char buf[finfo->stripe_count][4096];
409

410
    do {
411
        char newbuf[4096] = {
412
            0,
413
        };
414

415
        max_ret = 0;
416
        for (i = 0; i < finfo->stripe_count; i++) {
417
            memset(buf[i], 0, 4096);
418
            ret = read(finfo->fd[i], buf[i], 4096);
419
            if (ret > max_ret)
420
                max_ret = ret;
421
        }
422
        for (i = 0; i < max_ret; i++)
423
            for (j = 0; j < finfo->stripe_count; j++)
424
                newbuf[i] |= buf[j][i];
425
        write(target, newbuf, max_ret);
426
    } while (max_ret);
427

428
    return 0;
429
}
430

431
static int
432
generate_file(int target, struct file_stripe_info *finfo)
433
{
434
    if (finfo->coalesce)
435
        return generate_file_coalesce(target, finfo);
436

437
    return generate_file_traditional(target, finfo);
438
}
439

440
static void
441
usage(char *name)
442
{
443
    fprintf(stderr,
444
            "Usage: %s [-o <outputfile>] <inputfile1> "
445
            "<inputfile2> ...\n",
446
            name);
447
}
448

449
int
450
main(int argc, char *argv[])
451
{
452
    int file_count, opt;
453
    char *opath = NULL;
454
    int targetfd;
455
    struct file_stripe_info *finfo;
456

457
    while ((opt = getopt(argc, argv, "o:")) != -1) {
458
        switch (opt) {
459
            case 'o':
460
                opath = optarg;
461
                break;
462
            default:
463
                usage(argv[0]);
464
                return -1;
465
        }
466
    }
467

468
    file_count = argc - optind;
469

470
    if (!opath || !file_count) {
471
        usage(argv[0]);
472
        return -1;
473
    }
474

475
    finfo = validate_and_open_files(&argv[optind], file_count);
476
    if (!finfo)
477
        goto err;
478

479
    targetfd = open(opath, O_RDWR | O_CREAT, finfo->mode);
480
    if (targetfd < 0)
481
        goto err;
482

483
    if (generate_file(targetfd, finfo) < 0)
484
        goto err;
485

486
    if (fsync(targetfd) < 0)
487
        fprintf(stderr, "ERROR: %s\n", strerror(errno));
488
    if (close(targetfd) < 0)
489
        fprintf(stderr, "ERROR: %s\n", strerror(errno));
490

491
    close_files(finfo);
492
    free(finfo);
493

494
    return 0;
495

496
err:
497
    if (finfo) {
498
        close_files(finfo);
499
        free(finfo);
500
    }
501

502
    return -1;
503
}
504

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.