summaryrefslogtreecommitdiffstats
path: root/xlators/features/metadisp/src/metadisp-unlink.c
blob: 1f6a8eb35ce1a6d553cf412ba267c17c7b0781ae (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160

#include "metadisp.h"
#include <glusterfs/call-stub.h>

/**
 * The unlink flow in metadisp is complicated because we must
 * do ensure that UNLINK causes both the metadata objects
 * to get removed and the data objects to get removed.
 */

int32_t
metadisp_unlink_resume(call_frame_t *frame, xlator_t *this, loc_t *loc,
                       int xflag, dict_t *xdata)
{
    METADISP_TRACE("winding backend unlink to path %s", loc->path);
    STACK_WIND(frame, default_unlink_cbk, DATA_CHILD(this),
               DATA_CHILD(this)->fops->unlink, loc, xflag, xdata);
    return 0;
}

int32_t
metadisp_unlink_cbk(call_frame_t *frame, void *cookie, xlator_t *this,
                    int32_t op_ret, int32_t op_errno, struct iatt *preparent,
                    struct iatt *postparent, dict_t *xdata)
{
    METADISP_TRACE(". %d %d", op_ret, op_errno);

    int ret = 0;
    call_stub_t *stub = NULL;
    int nlink = 0;

    if (cookie) {
        stub = cookie;
    }

    if (op_ret != 0) {
        goto unwind;
    }

    if (stub->poison) {
        call_stub_destroy(stub);
        stub = NULL;
        return 0;
    }

    ret = dict_get_uint32(xdata, GF_RESPONSE_LINK_COUNT_XDATA, &nlink);
    if (ret != 0) {
        op_errno = EINVAL;
        op_ret = -1;
        goto unwind;
    }
    METADISP_TRACE("frontend hardlink count %d %d", ret, nlink);
    if (nlink > 1) {
        goto unwind;
    }

    call_resume(stub);
    return 0;

unwind:
    if (stub) {
        call_stub_destroy(stub);
    }
    STACK_UNWIND_STRICT(unlink, frame, op_ret, op_errno, preparent, postparent,
                        xdata);
    return 0;
}

int32_t
metadisp_unlink_lookup_cbk(call_frame_t *frame, void *cookie, xlator_t *this,
                           int32_t op_ret, int32_t op_errno, inode_t *inode,
                           struct iatt *buf, dict_t *xdata,
                           struct iatt *postparent)
{
    call_stub_t *stub = NULL;

    if (cookie) {
        stub = cookie;
    }

    if (op_ret != 0) {
        goto unwind;
    }

    // fail fast on empty gfid so we don't loop forever
    if (gf_uuid_is_null(buf->ia_gfid)) {
        op_ret = -1;
        op_errno = ENODATA;
        goto unwind;
    }

    // fill gfid since the stub is incomplete
    memcpy(stub->args.loc.gfid, buf->ia_gfid, sizeof(uuid_t));
    memcpy(stub->args.loc.pargfid, postparent->ia_gfid, sizeof(uuid_t));

    if (stub->poison) {
        call_stub_destroy(stub);
        stub = NULL;
        return 0;
    }

    call_resume(stub);
    return 0;

unwind:
    if (stub) {
        call_stub_destroy(stub);
    }
    STACK_UNWIND_STRICT(unlink, frame, op_ret, op_errno, NULL, NULL, NULL);
    return 0;
}

int32_t
metadisp_unlink(call_frame_t *frame, xlator_t *this, loc_t *loc, int xflag,
                dict_t *xdata)
{
    call_stub_t *stub = NULL;
    loc_t backend_loc = {
        0,
    };

    if (gf_uuid_is_null(loc->gfid)) {
        METADISP_TRACE("winding lookup for unlink to path %s", loc->path);

        // loop back to ourselves after a lookup
        stub = fop_unlink_stub(frame, metadisp_unlink, loc, xflag, xdata);
        STACK_WIND_COOKIE(frame, metadisp_unlink_lookup_cbk, stub,
                          METADATA_CHILD(this),
                          METADATA_CHILD(this)->fops->lookup, loc, xdata);
        return 0;
    }

    if (build_backend_loc(loc->gfid, loc, &backend_loc)) {
        goto unwind;
    }

    //
    // ensure we get the link count on the unlink response, so we can
    // account for hardlinks before winding to the backend.
    // NOTE:
    //   multiple xlators use GF_REQUEST_LINK_COUNT_XDATA. confirmation
    //   is needed to ensure that multiple requests will work in the same
    //   xlator stack.
    //
    if (!xdata) {
        xdata = dict_new();
    }
    dict_set_int32(xdata, GF_REQUEST_LINK_COUNT_XDATA, 1);

    METADISP_TRACE("winding frontend unlink to path %s", loc->path);
    stub = fop_unlink_stub(frame, metadisp_unlink_resume, &backend_loc, xflag,
                           xdata);

    STACK_WIND_COOKIE(frame, metadisp_unlink_cbk, stub, METADATA_CHILD(this),
                      METADATA_CHILD(this)->fops->unlink, loc, xflag, xdata);
    return 0;
unwind:
    STACK_UNWIND_STRICT(unlink, frame, -1, EINVAL, NULL, NULL, NULL);
    return 0;
}