-
Notifications
You must be signed in to change notification settings - Fork 0
/
hacksm_migrate.c
330 lines (275 loc) · 8.17 KB
/
hacksm_migrate.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
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
/*
a test implementation of a HSM migrate tool
Andrew Tridgell August 2008
*/
#include "hacksm.h"
#define SESSION_NAME "hacksm_migrate"
static struct {
dm_sessid_t sid;
dm_token_t token;
} dmapi = {
.sid = DM_NO_SESSION
};
static struct hsm_store_context *store_ctx;
/*
if we exit unexpectedly then we need to cleanup any rights we held
by reponding to our userevent
*/
static void hsm_term_handler(int signal)
{
if (!DM_TOKEN_EQ(dmapi.token,DM_NO_TOKEN)) {
dm_respond_event(dmapi.sid, dmapi.token, DM_RESP_CONTINUE, 0, 0, NULL);
dmapi.token = DM_NO_TOKEN;
}
printf("Got signal %d - exiting\n", signal);
exit(1);
}
/*
initialise the DMAPI connection
*/
static void hsm_init(void)
{
char *dmapi_version = NULL;
int ret;
ret = dm_init_service(&dmapi_version);
if (ret != 0) {
printf("Failed to init dmapi\n");
exit(1);
}
printf("Initialised DMAPI version '%s'\n", dmapi_version);
hsm_recover_session(SESSION_NAME, &dmapi.sid);
store_ctx = hsm_store_init();
if (store_ctx == NULL) {
printf("Unable to open HSM store - %s\n", strerror(errno));
exit(1);
}
if (hsm_store_connect(store_ctx, "/gpfs") != 0) {
printf("Failed to connect to HSM store\n");
exit(1);
}
}
/*
migrate one file
*/
static int hsm_migrate(const char *path)
{
int ret;
void *hanp = NULL;
size_t hlen = 0;
dm_attrname_t attrname;
uint8_t buf[0x1000];
size_t rlen;
struct stat st;
struct hsm_attr h;
dm_region_t region;
dm_boolean_t exactFlag;
off_t ofs;
int retval = 1;
struct hsm_store_handle *handle;
dmapi.token = DM_NO_TOKEN;
ret = dm_path_to_handle(discard_const(path), &hanp, &hlen);
if (ret != 0) {
printf("dm_path_to_handle failed for %s - %s\n", path, strerror(errno));
exit(1);
}
/* we create a user event which we use to gain exclusive
rights on the file */
ret = dm_create_userevent(dmapi.sid, 0, NULL, &dmapi.token);
if (ret != 0) {
printf("dm_create_userevent failed for %s - %s\n", path, strerror(errno));
exit(1);
}
/* getting an exclusive right first guarantees that two
migrate commands don't happen at the same time on the same
file, and also guarantees that a recall isn't happening at
the same time. We then downgrade to a shared right
immediately, which still gives the same guarantee, but
means that any reads on the file can proceeed while we are
saving away the data during the migrate */
ret = dm_request_right(dmapi.sid, hanp, hlen, dmapi.token, DM_RR_WAIT, DM_RIGHT_EXCL);
if (ret != 0) {
printf("dm_request_right failed for %s - %s\n", path, strerror(errno));
goto respond;
}
/* now downgrade the right - reads on the file can then proceed during the
expensive migration step */
ret = dm_downgrade_right(dmapi.sid, hanp, hlen, dmapi.token);
if (ret != 0) {
printf("dm_downgrade_right failed for %s - %s\n", path, strerror(errno));
goto respond;
}
memset(attrname.an_chars, 0, DM_ATTR_NAME_SIZE);
strncpy((char*)attrname.an_chars, HSM_ATTRNAME, DM_ATTR_NAME_SIZE);
/* get any existing attribute on the file */
ret = dm_get_dmattr(dmapi.sid, hanp, hlen, dmapi.token, &attrname,
sizeof(h), &h, &rlen);
if (ret != 0 && errno != ENOENT) {
printf("dm_get_dmattr failed for %s - %s\n", path, strerror(errno));
goto respond;
}
/* check it is valid */
if (ret == 0) {
if (strncmp(h.magic, HSM_MAGIC, sizeof(h.magic)) != 0) {
printf("Bad magic '%*.*s'\n", (int)sizeof(h.magic), (int)sizeof(h.magic), h.magic);
exit(1);
}
if (h.state == HSM_STATE_START) {
/* a migration has died on this file */
printf("Continuing migration of partly migrated file\n");
hsm_store_remove(store_ctx, h.device, h.inode);
} else {
/* it is either fully migrated, or waiting recall */
printf("Not migrating already migrated file %s\n", path);
goto respond;
}
}
if (lstat(path, &st) != 0) {
printf("failed to stat %s - %s\n", path, strerror(errno));
goto respond;
}
if (!S_ISREG(st.st_mode)) {
printf("Not migrating non-regular file %s\n", path);
goto respond;
}
if (st.st_size == 0) {
printf("Not migrating file '%s' of size 0\n", path);
goto respond;
}
/* open up the store file */
handle = hsm_store_open(store_ctx, st.st_dev, st.st_ino, false);
if (handle == NULL) {
printf("Failed to open store file for %s - %s\n", path, strerror(errno));
goto respond;
}
/* read the file data and store it away */
ofs = 0;
while ((ret = dm_read_invis(dmapi.sid, hanp, hlen, dmapi.token, ofs, sizeof(buf), buf)) > 0) {
if (hsm_store_write(handle, buf, ret) != 0) {
printf("Failed to write to store for %s - %s\n", path, strerror(errno));
hsm_store_close(handle);
hsm_store_remove(store_ctx, st.st_dev, st.st_ino);
goto respond;
}
ofs += ret;
}
if (ret == -1) {
printf("failed dm_read_invis on %s - %s\n", path, strerror(errno));
hsm_store_close(handle);
hsm_store_remove(store_ctx, st.st_dev, st.st_ino);
goto respond;
}
hsm_store_close(handle);
/* now upgrade to a exclusive right on the file before we
change the dmattr and punch holes in the file. */
ret = dm_upgrade_right(dmapi.sid, hanp, hlen, dmapi.token);
if (ret != 0) {
printf("dm_upgrade_right failed for %s - %s\n", path, strerror(errno));
goto respond;
}
strncpy(h.magic, HSM_MAGIC, sizeof(h.magic));
h.size = st.st_size;
h.migrate_time = time(NULL);
h.device = st.st_dev;
h.inode = st.st_ino;
h.state = HSM_STATE_START;
/* mark the file as starting to migrate */
ret = dm_set_dmattr(dmapi.sid, hanp, hlen, dmapi.token, &attrname, 0,
sizeof(h), (void*)&h);
if (ret == -1) {
printf("failed dm_set_dmattr on %s - %s\n", path, strerror(errno));
hsm_store_remove(store_ctx, st.st_dev, st.st_ino);
goto respond;
}
/* mark the whole file as offline, including parts beyond EOF */
region.rg_offset = 0;
region.rg_size = 0; /* zero means the whole file */
region.rg_flags = DM_REGION_WRITE | DM_REGION_READ;
ret = dm_set_region(dmapi.sid, hanp, hlen, dmapi.token, 1, ®ion, &exactFlag);
if (ret == -1) {
printf("failed dm_set_region on %s - %s\n", path, strerror(errno));
hsm_store_remove(store_ctx, st.st_dev, st.st_ino);
goto respond;
}
/* this dm_get_dmattr() is not strictly necessary - it is just
paranoia */
ret = dm_get_dmattr(dmapi.sid, hanp, hlen, dmapi.token, &attrname,
sizeof(h), &h, &rlen);
if (ret != 0) {
printf("ERROR: Abandoning partial migrate - attribute gone!?\n");
goto respond;
}
if (h.state != HSM_STATE_START) {
printf("ERROR: Abandoning partial migrate - state=%d\n", h.state);
goto respond;
}
ret = dm_punch_hole(dmapi.sid, hanp, hlen, dmapi.token, 0, st.st_size);
if (ret == -1) {
printf("failed dm_punch_hole on %s - %s\n", path, strerror(errno));
hsm_store_remove(store_ctx, st.st_dev, st.st_ino);
goto respond;
}
h.state = HSM_STATE_MIGRATED;
/* mark the file as fully migrated */
ret = dm_set_dmattr(dmapi.sid, hanp, hlen, dmapi.token, &attrname,
0, sizeof(h), (void*)&h);
if (ret == -1) {
printf("failed dm_set_dmattr on %s - %s\n", path, strerror(errno));
hsm_store_remove(store_ctx, st.st_dev, st.st_ino);
goto respond;
}
printf("Migrated file '%s' of size %d\n", path, (int)st.st_size);
retval = 0;
respond:
/* destroy our userevent */
ret = dm_respond_event(dmapi.sid, dmapi.token, DM_RESP_CONTINUE, 0, 0, NULL);
if (ret == -1) {
printf("failed dm_respond_event on %s - %s\n", path, strerror(errno));
exit(1);
}
dmapi.token = DM_NO_TOKEN;
dm_handle_free(hanp, hlen);
return retval;
}
static void usage(void)
{
printf("Usage: hacksm_migrate <options> PATH..\n");
printf("\n\tOptions:\n");
printf("\t\t -c cleanup lost tokens\n");
exit(0);
}
int main(int argc, char * const argv[])
{
int opt, i, ret=0;
bool cleanup = false;
/* parse command-line options */
while ((opt = getopt(argc, argv, "hc")) != -1) {
switch (opt) {
case 'c':
cleanup = true;
break;
case 'h':
default:
usage();
break;
}
}
setlinebuf(stdout);
argv += optind;
argc -= optind;
hsm_init();
if (cleanup) {
hsm_cleanup_tokens(dmapi.sid, DM_RESP_CONTINUE, 0);
if (argc == 0) {
return 0;
}
}
signal(SIGTERM, hsm_term_handler);
signal(SIGINT, hsm_term_handler);
if (argc == 0) {
usage();
}
for (i=0;i<argc;i++) {
ret |= hsm_migrate(argv[i]);
}
return ret;
}