glusterfs

Форк
0
/
server-resolve.c 
617 строк · 18.0 Кб
1
/*
2
  Copyright (c) 2010-2013 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
#include "server.h"
12
#include "server-helpers.h"
13
#include "server-messages.h"
14

15
static void
16
server_resolve_all(call_frame_t *frame, server_state_t *state);
17
static int
18
resolve_entry_simple(call_frame_t *frame, server_state_t *state,
19
                     server_resolve_t *resolve);
20
static int
21
resolve_inode_simple(call_frame_t *frame, server_state_t *state,
22
                     server_resolve_t *resolve);
23
static void
24
resolve_continue(call_frame_t *frame, server_state_t *state,
25
                 server_resolve_t *resolve);
26
static int
27
resolve_anonfd_simple(call_frame_t *frame, server_state_t *state,
28
                      server_resolve_t *resolve);
29

30
static int
31
resolve_name_cbk(call_frame_t *frame, void *cookie, xlator_t *this, int op_ret,
32
                 int op_errno, inode_t *inode, struct iatt *buf, dict_t *xdata,
33
                 struct iatt *postparent)
34
{
35
    server_state_t *state = NULL;
36
    server_resolve_t *resolve = NULL;
37
    inode_t *link_inode = NULL;
38
    loc_t *resolve_loc = NULL;
39

40
    state = CALL_STATE(frame);
41
    resolve = state->resolve_now;
42
    resolve_loc = &resolve->resolve_loc;
43

44
    if (op_ret == -1) {
45
        if (op_errno == ENOENT) {
46
            gf_msg_debug(this->name, op_errno, "%s/%s: failed to resolve",
47
                         uuid_utoa(resolve_loc->pargfid), resolve_loc->name);
48
            if (resolve->type == RESOLVE_NOT) {
49
                do {
50
                    inode = inode_grep(state->itable, resolve_loc->parent,
51
                                       resolve->bname);
52

53
                    if (inode) {
54
                        gf_msg_debug(this->name, 0,
55
                                     "%s/%s: "
56
                                     "removing stale dentry",
57
                                     uuid_utoa(resolve_loc->pargfid),
58
                                     resolve->bname);
59
                        inode_unlink(inode, resolve_loc->parent,
60
                                     resolve->bname);
61
                    }
62
                } while (inode);
63
            }
64
        } else {
65
            gf_msg(this->name, GF_LOG_WARNING, op_errno,
66
                   PS_MSG_GFID_RESOLVE_FAILED,
67
                   "%s/%s: failed to "
68
                   "resolve (%s)",
69
                   uuid_utoa(resolve_loc->pargfid), resolve_loc->name,
70
                   strerror(op_errno));
71
        }
72
        goto out;
73
    }
74

75
    link_inode = inode_link(inode, resolve_loc->parent, resolve_loc->name, buf);
76

77
    if (!link_inode)
78
        goto out;
79

80
    inode_lookup(link_inode);
81

82
    inode_unref(link_inode);
83

84
out:
85
    loc_wipe(resolve_loc);
86

87
    resolve_continue(frame, state, resolve);
88
    return 0;
89
}
90

91
static int
92
resolve_name(call_frame_t *frame, inode_t *parent, server_state_t *state,
93
             server_resolve_t *resolve)
94
{
95
    loc_t *resolve_loc = NULL;
96
    dict_t *dict = NULL;
97

98
    resolve_loc = &resolve->resolve_loc;
99
    resolve_loc->parent = inode_ref(parent);
100
    gf_uuid_copy(resolve_loc->pargfid, resolve_loc->parent->gfid);
101

102
    resolve_loc->name = resolve->bname;
103

104
    resolve_loc->inode = server_inode_new(state->itable, resolve_loc->gfid);
105

106
    inode_path(resolve_loc->parent, resolve_loc->name,
107
               (char **)&resolve_loc->path);
108

109
    if (state->xdata) {
110
        dict = dict_copy_with_ref(state->xdata, NULL);
111
        if (!dict)
112
            gf_msg(frame->this->name, GF_LOG_ERROR, ENOMEM, PS_MSG_NO_MEMORY,
113
                   "BUG: dict allocation failed (pargfid: %s, name: %s), "
114
                   "still continuing",
115
                   uuid_utoa(resolve_loc->gfid), resolve_loc->name);
116
    }
117

118
    STACK_WIND(frame, resolve_name_cbk, frame->root->client->bound_xl,
119
               frame->root->client->bound_xl->fops->lookup,
120
               &resolve->resolve_loc, dict);
121
    if (dict)
122
        dict_unref(dict);
123
    return 0;
124
}
125

126
static int
127
resolve_gfid_cbk(call_frame_t *frame, void *cookie, xlator_t *this, int op_ret,
128
                 int op_errno, inode_t *inode, struct iatt *buf, dict_t *xdata,
129
                 struct iatt *postparent)
130
{
131
    server_state_t *state = NULL;
132
    server_resolve_t *resolve = NULL;
133
    inode_t *link_inode = NULL;
134
    loc_t *resolve_loc = NULL;
135

136
    state = CALL_STATE(frame);
137
    resolve = state->resolve_now;
138
    resolve_loc = &resolve->resolve_loc;
139

140
    if (op_ret == -1) {
141
        if (op_errno == ENOENT) {
142
            gf_msg_debug(this->name, op_errno, "%s: failed to resolve",
143
                         uuid_utoa(resolve_loc->gfid));
144
        } else {
145
            gf_msg(this->name, GF_LOG_WARNING, op_errno,
146
                   PS_MSG_GFID_RESOLVE_FAILED, "%s: failed to resolve (%s)",
147
                   uuid_utoa(resolve_loc->gfid), strerror(op_errno));
148
        }
149
        loc_wipe(&resolve->resolve_loc);
150
        goto out;
151
    }
152

153
    link_inode = inode_link(inode, NULL, NULL, buf);
154

155
    if (!link_inode) {
156
        loc_wipe(resolve_loc);
157
        goto out;
158
    }
159

160
    inode_lookup(link_inode);
161

162
    /* wipe the loc only after the inode has been linked to the inode
163
       table. Otherwise before inode gets linked to the inode table,
164
       inode would have been unrefed (this might have been destroyed
165
       if refcount becomes 0, and put back to mempool). So once the
166
       inode gets destroyed, inode_link is a redundant operation. But
167
       without knowing that the destroyed inode's pointer is saved in
168
       the resolved_loc as parent (while constructing loc for resolving
169
       the entry) and the inode_new call for resolving the entry will
170
       return the same pointer to the inode as the parent (because in
171
       reality the inode is a free inode present in cold list of the
172
       inode mem-pool).
173
    */
174
    loc_wipe(resolve_loc);
175

176
    if (gf_uuid_is_null(resolve->pargfid)) {
177
        inode_unref(link_inode);
178
        goto out;
179
    }
180

181
    resolve_name(frame, link_inode, state, resolve);
182
    inode_unref(link_inode);
183

184
    return 0;
185
out:
186
    resolve_continue(frame, state, resolve);
187
    return 0;
188
}
189

190
static void
191
resolve_gfid(call_frame_t *frame, server_state_t *state,
192
             server_resolve_t *resolve)
193
{
194
    loc_t *resolve_loc = NULL;
195
    dict_t *xdata = NULL;
196

197
    resolve_loc = &resolve->resolve_loc;
198

199
    if (!gf_uuid_is_null(resolve->pargfid))
200
        gf_uuid_copy(resolve_loc->gfid, resolve->pargfid);
201
    else if (!gf_uuid_is_null(resolve->gfid))
202
        gf_uuid_copy(resolve_loc->gfid, resolve->gfid);
203

204
    resolve_loc->inode = server_inode_new(state->itable, resolve_loc->gfid);
205
    (void)loc_path(resolve_loc, NULL);
206

207
    if (state->xdata) {
208
        xdata = dict_copy_with_ref(state->xdata, NULL);
209
        if (!xdata)
210
            gf_msg(frame->this->name, GF_LOG_ERROR, ENOMEM, PS_MSG_NO_MEMORY,
211
                   "BUG: dict allocation failed (gfid: %s), "
212
                   "still continuing",
213
                   uuid_utoa(resolve_loc->gfid));
214
    }
215

216
    STACK_WIND(frame, resolve_gfid_cbk, frame->root->client->bound_xl,
217
               frame->root->client->bound_xl->fops->lookup,
218
               &resolve->resolve_loc, xdata);
219

220
    if (xdata)
221
        dict_unref(xdata);
222
}
223

224
static void
225
resolve_continue(call_frame_t *frame, server_state_t *state,
226
                 server_resolve_t *resolve)
227
{
228
    int ret = 0;
229

230
    resolve->op_ret = 0;
231
    resolve->op_errno = 0;
232

233
    if (resolve->fd_no != -1) {
234
        ret = resolve_anonfd_simple(frame, state, resolve);
235
        goto out;
236
    } else if (!gf_uuid_is_null(resolve->pargfid))
237
        ret = resolve_entry_simple(frame, state, resolve);
238
    else if (!gf_uuid_is_null(resolve->gfid))
239
        ret = resolve_inode_simple(frame, state, resolve);
240
    if (ret)
241
        gf_msg_debug(frame->this->name, 0,
242
                     "return value of resolve_*_"
243
                     "simple %d",
244
                     ret);
245

246
    loc_touchup(state->loc_now, resolve->bname);
247
out:
248
    server_resolve_all(frame, state);
249
}
250

251
/*
252
  Check if the requirements are fulfilled by entries in the inode cache itself
253
  Return value:
254
  <= 0 - simple resolution was decisive and complete (either success or failure)
255
  > 0  - indecisive, need to perform deep resolution
256
*/
257

258
static int
259
resolve_entry_simple(call_frame_t *frame, server_state_t *state,
260
                     server_resolve_t *resolve)
261
{
262
    inode_t *parent = NULL;
263
    inode_t *inode = NULL;
264
    int ret = 0;
265

266
    parent = inode_find(state->itable, resolve->pargfid);
267
    if (!parent) {
268
        /* simple resolution is indecisive. need to perform
269
           deep resolution */
270
        resolve->op_ret = -1;
271
        resolve->op_errno = ESTALE;
272
        ret = 1;
273
        goto out;
274
    }
275

276
    if (parent->ia_type != IA_IFDIR) {
277
        /* Parent type should be 'directory', and nothing else */
278
        gf_msg(frame->this->name, GF_LOG_ERROR, EPERM,
279
               PS_MSG_GFID_RESOLVE_FAILED, "%s: parent type not directory (%d)",
280
               uuid_utoa(parent->gfid), parent->ia_type);
281
        resolve->op_ret = -1;
282
        resolve->op_errno = EPERM;
283
        ret = 1;
284
        goto out;
285
    }
286

287
    /* expected @parent was found from the inode cache */
288
    gf_uuid_copy(state->loc_now->pargfid, resolve->pargfid);
289
    state->loc_now->parent = inode_ref(parent);
290
    if (strchr(resolve->bname, '/')) {
291
        /* basename should be a string (without '/') in a directory,
292
           it can't span multiple levels. This can also lead to
293
           resolving outside the parent's tree, which is not allowed */
294
        gf_msg(frame->this->name, GF_LOG_ERROR, EPERM,
295
               PS_MSG_GFID_RESOLVE_FAILED,
296
               "%s: basename sent by client not allowed", resolve->bname);
297
        resolve->op_ret = -1;
298
        resolve->op_errno = EPERM;
299
        ret = 1;
300
        goto out;
301
    }
302

303
    state->loc_now->name = resolve->bname;
304

305
    inode = inode_grep(state->itable, parent, resolve->bname);
306
    if (!inode) {
307
        switch (resolve->type) {
308
            case RESOLVE_DONTCARE:
309
            case RESOLVE_NOT:
310
                ret = 0;
311
                break;
312
            case RESOLVE_MAY:
313
                ret = 2;
314
                break;
315
            default:
316
                resolve->op_ret = -1;
317
                resolve->op_errno = ENOENT;
318
                ret = 2;
319
                break;
320
        }
321

322
        goto out;
323
    }
324

325
    if (resolve->type == RESOLVE_NOT) {
326
        gf_msg_debug(frame->this->name, 0,
327
                     "inode (pointer: %p gfid:%s found"
328
                     " for path (%s) while type is RESOLVE_NOT. "
329
                     "Performing lookup on backend to rule out any "
330
                     "possible stale dentries in inode table",
331
                     inode, uuid_utoa(inode->gfid), resolve->path);
332
        resolve->op_ret = -1;
333
        resolve->op_errno = EEXIST;
334
        ret = 1;
335
        goto out;
336
    }
337

338
    ret = 0;
339

340
    state->loc_now->inode = inode_ref(inode);
341

342
out:
343
    if (parent)
344
        inode_unref(parent);
345

346
    if (inode)
347
        inode_unref(inode);
348

349
    return ret;
350
}
351

352
static void
353
server_resolve_entry(call_frame_t *frame, server_state_t *state,
354
                     server_resolve_t *resolve)
355
{
356
    int ret = 0;
357
    inode_t *parent = NULL;
358

359
    ret = resolve_entry_simple(frame, state, resolve);
360

361
    if (ret > 0) {
362
        if (ret == 2) {
363
            parent = inode_ref(state->loc_now->parent);
364
        }
365
        /*Wipe state->loc_now before calling resolve_xxxx()*/
366
        loc_wipe(state->loc_now);
367
        if (parent) {
368
            resolve_name(frame, parent, state, resolve);
369
            inode_unref(parent);
370
        } else {
371
            resolve_gfid(frame, state, resolve);
372
        }
373
    } else {
374
        loc_touchup(state->loc_now, resolve->bname);
375
        server_resolve_all(frame, state);
376
    }
377
}
378

379
static int
380
resolve_inode_simple(call_frame_t *frame, server_state_t *state,
381
                     server_resolve_t *resolve)
382
{
383
    inode_t *inode = NULL;
384
    int ret = 0;
385

386
    inode = inode_find(state->itable, resolve->gfid);
387

388
    if (!inode) {
389
        if (resolve->type == RESOLVE_DONTCARE) {
390
            gf_uuid_copy(state->loc_now->gfid, resolve->gfid);
391
        } else {
392
            resolve->op_ret = -1;
393
            resolve->op_errno = ESTALE;
394
            ret = 1;
395
        }
396
        goto out;
397
    }
398

399
    state->loc_now->inode = inode_ref(inode);
400
    gf_uuid_copy(state->loc_now->gfid, resolve->gfid);
401

402
out:
403
    if (inode)
404
        inode_unref(inode);
405

406
    return ret;
407
}
408

409
static void
410
server_resolve_inode(call_frame_t *frame, server_state_t *state,
411
                     server_resolve_t *resolve)
412
{
413
    int ret = 0;
414
    loc_t *loc = NULL;
415

416
    ret = resolve_inode_simple(frame, state, resolve);
417

418
    if (ret > 0) {
419
        loc = state->loc_now;
420
        loc_wipe(loc);
421
        resolve_gfid(frame, state, resolve);
422
    } else {
423
        loc_touchup(state->loc_now, resolve->bname);
424
        server_resolve_all(frame, state);
425
    }
426
}
427

428
static int
429
resolve_anonfd_simple(call_frame_t *frame, server_state_t *state,
430
                      server_resolve_t *resolve)
431
{
432
    inode_t *inode = NULL;
433
    int ret = 0;
434

435
    inode = inode_find(state->itable, resolve->gfid);
436

437
    if (!inode) {
438
        resolve->op_ret = -1;
439
        resolve->op_errno = ENOENT;
440
        ret = 1;
441
        gf_msg_debug("server", 0,
442
                     "inode for the gfid"
443
                     "(%s) is not found. anonymous fd creation failed",
444
                     uuid_utoa(resolve->gfid));
445
        goto out;
446
    }
447

448
    if (frame->root->op == GF_FOP_READ || frame->root->op == GF_FOP_WRITE)
449
        state->fd = fd_anonymous_with_flags(inode, state->flags);
450
    else
451
        state->fd = fd_anonymous(inode);
452
out:
453
    if (inode)
454
        inode_unref(inode);
455

456
    return ret;
457
}
458

459
static void
460
server_resolve_anonfd(call_frame_t *frame, server_state_t *state,
461
                      server_resolve_t *resolve)
462
{
463
    int ret = 0;
464
    loc_t *loc = NULL;
465

466
    ret = resolve_anonfd_simple(frame, state, resolve);
467

468
    if (ret > 0) {
469
        loc = state->loc_now;
470
        loc_wipe(loc);
471
        resolve_gfid(frame, state, resolve);
472
    } else {
473
        server_resolve_all(frame, state);
474
    }
475
}
476

477
static void
478
server_resolve_fd(call_frame_t *frame, server_state_t *state,
479
                  server_resolve_t *resolve)
480
{
481
    server_ctx_t *serv_ctx = NULL;
482
    client_t *client = NULL;
483
    uint64_t fd_no;
484

485
    fd_no = resolve->fd_no;
486

487
    if (fd_no == GF_ANON_FD_NO) {
488
        server_resolve_anonfd(frame, state, resolve);
489
        return;
490
    }
491

492
    client = frame->root->client;
493

494
    serv_ctx = server_ctx_get(client, client->this);
495

496
    if (serv_ctx == NULL) {
497
        gf_msg("", GF_LOG_INFO, ENOMEM, PS_MSG_NO_MEMORY,
498
               "server_ctx_get() failed");
499
        resolve->op_ret = -1;
500
        resolve->op_errno = ENOMEM;
501
        return;
502
    }
503

504
    /*
505
     * With copy_file_range, there will be 2 fds to resolve.
506
     * This same function is called to resolve both the source
507
     * fd and the destination fd. As of now, this function does
508
     * not have any mechanism to distinguish between the 2 fds
509
     * being resolved except for checking the value of state->fd.
510
     * The assumption is that, if source fd the one which is
511
     * being resolved here, then state->fd would be NULL. If it
512
     * is not NULL, then it is the destination fd which is being
513
     * resolved.
514
     * This  method (provided the above assumption is true) is
515
     * to achieve the ability to distinguish between 2 fds with
516
     * minimum changes being done to this function. If this way
517
     * is not correct, then more changes might be needed.
518
     */
519
    if (!state->fd) {
520
        state->fd = gf_fd_fdptr_get(serv_ctx->fdtable, fd_no);
521
        if (!state->fd) {
522
            gf_msg("", GF_LOG_INFO, EBADF, PS_MSG_FD_NOT_FOUND,
523
                   "fd not "
524
                   "found in context");
525
            resolve->op_ret = -1;
526
            resolve->op_errno = EBADF;
527
        }
528
    } else {
529
        state->fd_out = gf_fd_fdptr_get(serv_ctx->fdtable, fd_no);
530
        if (!state->fd_out) {
531
            gf_msg("", GF_LOG_INFO, EBADF, PS_MSG_FD_NOT_FOUND,
532
                   "fd not "
533
                   "found in context");
534
            resolve->op_ret = -1;
535
            resolve->op_errno = EBADF;
536
        }
537
    }
538

539
    server_resolve_all(frame, state);
540
}
541

542
static void
543
server_resolve(call_frame_t *frame, server_state_t *state)
544
{
545
    server_resolve_t *resolve = NULL;
546

547
    resolve = state->resolve_now;
548

549
    if (resolve->fd_no != -1) {
550
        server_resolve_fd(frame, state, resolve);
551

552
    } else if (!gf_uuid_is_null(resolve->pargfid)) {
553
        server_resolve_entry(frame, state, resolve);
554

555
    } else if (!gf_uuid_is_null(resolve->gfid)) {
556
        server_resolve_inode(frame, state, resolve);
557

558
    } else {
559
        if (resolve == &state->resolve)
560
            gf_msg(frame->this->name, GF_LOG_WARNING, 0, PS_MSG_INVALID_ENTRY,
561
                   "no resolution type for %s (%s)", resolve->path,
562
                   gf_fop_list[frame->root->op]);
563

564
        resolve->op_ret = -1;
565
        resolve->op_errno = EINVAL;
566

567
        server_resolve_all(frame, state);
568
    }
569
}
570

571
static void
572
server_resolve_done(call_frame_t *frame, server_state_t *state)
573
{
574
    server_print_request(frame);
575

576
    state->resume_fn(frame, frame->root->client->bound_xl);
577
}
578

579
/*
580
 * This function is called multiple times, once per resolving one location/fd.
581
 * state->resolve_now is used to decide which location/fd is to be resolved now
582
 */
583
static void
584
server_resolve_all(call_frame_t *frame, server_state_t *state)
585
{
586
    if (state->resolve_now == NULL) {
587
        state->resolve_now = &state->resolve;
588
        state->loc_now = &state->loc;
589

590
        server_resolve(frame, state);
591

592
    } else if (state->resolve_now == &state->resolve) {
593
        state->resolve_now = &state->resolve2;
594
        state->loc_now = &state->loc2;
595

596
        server_resolve(frame, state);
597

598
    } else if (state->resolve_now == &state->resolve2) {
599
        server_resolve_done(frame, state);
600

601
    } else {
602
        gf_msg(frame->this->name, GF_LOG_ERROR, EINVAL, PS_MSG_INVALID_ENTRY,
603
               "Invalid pointer for "
604
               "state->resolve_now");
605
    }
606
}
607

608
void
609
resolve_and_resume(call_frame_t *frame, server_resume_fn_t fn)
610
{
611
    server_state_t *state = NULL;
612

613
    state = CALL_STATE(frame);
614
    state->resume_fn = fn;
615

616
    server_resolve_all(frame, state);
617
}
618

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

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

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

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