-
Notifications
You must be signed in to change notification settings - Fork 10
/
Copy pathdeferred.c
139 lines (104 loc) · 3.96 KB
/
deferred.c
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
/*
runfs: a self-cleaning filesystem for runtime state.
Copyright (C) 2015 Jude Nelson
This program is dual-licensed: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License version 3 or later as
published by the Free Software Foundation. For the terms of this
license, see LICENSE.LGPLv3+ or <http://www.gnu.org/licenses/>.
You are free to use this program under the terms of the GNU Lesser General
Public License, but WITHOUT ANY WARRANTY; without even the implied
warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU Lesser General Public License for more details.
Alternatively, you are free to use this program under the terms of the
Internet Software Consortium License, but WITHOUT ANY WARRANTY; without
even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
For the terms of this license, see LICENSE.ISC or
<http://www.isc.org/downloads/software-support-policy/isc-license/>.
*/
#include "deferred.h"
#include "runfs.h"
// deferred remove-all context
struct runfs_deferred_remove_ctx {
struct fskit_core* core;
char* fs_path; // path to the entry to remove
fskit_entry_set* children; // the (optional) children to remove (not yet garbage-collected)
};
// helper to asynchronously try to unlink an inode and its children
static int runfs_deferred_remove_cb( struct runfs_wreq* wreq, void* cls ) {
struct runfs_deferred_remove_ctx* ctx = (struct runfs_deferred_remove_ctx*)cls;
struct fskit_detach_ctx* dctx = NULL;
int rc = 0;
runfs_debug("DEFERRED: remove '%s'\n", ctx->fs_path );
// remove the children
if( ctx->children != NULL ) {
dctx = fskit_detach_ctx_new();
if( dctx == NULL ) {
return -ENOMEM;
}
rc = fskit_detach_ctx_init( dctx );
if( rc != 0 ) {
return rc;
}
// proceed to detach
while( true ) {
rc = fskit_detach_all_ex( ctx->core, ctx->fs_path, &ctx->children, dctx );
if( rc == 0 ) {
break;
}
else if( rc == -ENOMEM ) {
continue;
}
else {
break;
}
}
fskit_detach_ctx_free( dctx );
runfs_safe_free( dctx );
fskit_entry_set_free( ctx->children );
}
runfs_safe_free( ctx->fs_path );
runfs_safe_free( ctx );
return 0;
}
// Garbage-collect the given inode, and queue it for unlinkage.
// If the inode is a directory, recursively garbage-collect its children as well, and queue them and their descendents for unlinkage
// return 0 on success
// NOTE: child must be write-locked
int runfs_deferred_remove( struct runfs_state* runfs, char const* child_path, struct fskit_entry* child ) {
struct runfs_deferred_remove_ctx* ctx = NULL;
struct fskit_core* core = runfs->core;
struct runfs_wreq* work = NULL;
fskit_entry_set* children = NULL;
int rc = 0;
// asynchronously unlink it and its children
ctx = RUNFS_CALLOC( struct runfs_deferred_remove_ctx, 1 );
if( ctx == NULL ) {
return -ENOMEM;
}
work = RUNFS_CALLOC( struct runfs_wreq, 1 );
if( work == NULL ) {
runfs_safe_free( ctx );
return -ENOMEM;
}
// set up the deferred unlink request
ctx->core = core;
ctx->fs_path = strdup( child_path );
if( ctx->fs_path == NULL ) {
runfs_safe_free( work );
runfs_safe_free( ctx );
return -ENOMEM;
}
// garbage-collect this child
rc = fskit_entry_tag_garbage( child, &children );
if( rc != 0 ) {
runfs_safe_free( ctx );
runfs_safe_free( work );
runfs_error("fskit_entry_garbage_collect('%s') rc = %d\n", child_path, rc );
return rc;
}
ctx->children = children;
// deferred removal
runfs_wreq_init( work, runfs_deferred_remove_cb, ctx );
runfs_wq_add( runfs->deferred_unlink_wq, work );
return 0;
}