1 6f4d00ee 2013-09-23 0intro #include "stdinc.h"
2 6f4d00ee 2013-09-23 0intro #include "dat.h"
3 6f4d00ee 2013-09-23 0intro #include "fns.h"
4 6f4d00ee 2013-09-23 0intro #include "error.h"
6 6f4d00ee 2013-09-23 0intro static void fsMetaFlush(void *a);
7 6f4d00ee 2013-09-23 0intro static Snap *snapInit(Fs*);
8 6f4d00ee 2013-09-23 0intro static void snapClose(Snap*);
11 4b576658 2013-09-23 0intro fsOpen(char *file, VtConn *z, long ncache, int mode)
13 6f4d00ee 2013-09-23 0intro int fd, m;
14 6f4d00ee 2013-09-23 0intro uchar oscore[VtScoreSize];
15 6f4d00ee 2013-09-23 0intro Block *b, *bs;
16 6f4d00ee 2013-09-23 0intro Disk *disk;
18 6f4d00ee 2013-09-23 0intro Super super;
19 4b576658 2013-09-23 0intro char e[ERRMAX];
21 6f4d00ee 2013-09-23 0intro switch(mode){
23 4b576658 2013-09-23 0intro werrstr(EBadMode);
24 6f4d00ee 2013-09-23 0intro return nil;
25 6f4d00ee 2013-09-23 0intro case OReadOnly:
26 6f4d00ee 2013-09-23 0intro m = OREAD;
28 6f4d00ee 2013-09-23 0intro case OReadWrite:
29 6f4d00ee 2013-09-23 0intro m = ORDWR;
32 6f4d00ee 2013-09-23 0intro fd = open(file, m);
33 6f4d00ee 2013-09-23 0intro if(fd < 0){
34 4b576658 2013-09-23 0intro werrstr("open %s: %r", file);
35 6f4d00ee 2013-09-23 0intro return nil;
38 6f4d00ee 2013-09-23 0intro bwatchInit();
39 6f4d00ee 2013-09-23 0intro disk = diskAlloc(fd);
40 6f4d00ee 2013-09-23 0intro if(disk == nil){
41 4b576658 2013-09-23 0intro werrstr("diskAlloc: %r");
42 6f4d00ee 2013-09-23 0intro close(fd);
43 6f4d00ee 2013-09-23 0intro return nil;
46 4b576658 2013-09-23 0intro fs = vtmallocz(sizeof(Fs));
47 6f4d00ee 2013-09-23 0intro fs->mode = mode;
48 4b576658 2013-09-23 0intro fs->name = vtstrdup(file);
49 6f4d00ee 2013-09-23 0intro fs->blockSize = diskBlockSize(disk);
50 6f4d00ee 2013-09-23 0intro fs->cache = cacheAlloc(disk, z, ncache, mode);
51 6f4d00ee 2013-09-23 0intro if(mode == OReadWrite && z)
52 6f4d00ee 2013-09-23 0intro fs->arch = archInit(fs->cache, disk, fs, z);
53 6f4d00ee 2013-09-23 0intro fs->z = z;
55 6f4d00ee 2013-09-23 0intro b = cacheLocal(fs->cache, PartSuper, 0, mode);
56 6f4d00ee 2013-09-23 0intro if(b == nil)
58 6f4d00ee 2013-09-23 0intro if(!superUnpack(&super, b->data)){
59 6f4d00ee 2013-09-23 0intro blockPut(b);
60 4b576658 2013-09-23 0intro werrstr("bad super block");
63 6f4d00ee 2013-09-23 0intro blockPut(b);
65 6f4d00ee 2013-09-23 0intro fs->ehi = super.epochHigh;
66 6f4d00ee 2013-09-23 0intro fs->elo = super.epochLow;
68 6f4d00ee 2013-09-23 0intro //fprint(2, "%s: fs->ehi %d fs->elo %d active=%d\n", argv0, fs->ehi, fs->elo, super.active);
70 6f4d00ee 2013-09-23 0intro fs->source = sourceRoot(fs, super.active, mode);
71 6f4d00ee 2013-09-23 0intro if(fs->source == nil){
73 6f4d00ee 2013-09-23 0intro * Perhaps it failed because the block is copy-on-write.
74 6f4d00ee 2013-09-23 0intro * Do the copy and try again.
76 4b576658 2013-09-23 0intro rerrstr(e, sizeof e);
77 4b576658 2013-09-23 0intro if(mode == OReadOnly || strcmp(e, EBadRoot) != 0)
79 6f4d00ee 2013-09-23 0intro b = cacheLocalData(fs->cache, super.active, BtDir, RootTag,
80 6f4d00ee 2013-09-23 0intro OReadWrite, 0);
81 6f4d00ee 2013-09-23 0intro if(b == nil){
82 4b576658 2013-09-23 0intro werrstr("cacheLocalData: %r");
85 6f4d00ee 2013-09-23 0intro if(b->l.epoch == fs->ehi){
86 6f4d00ee 2013-09-23 0intro blockPut(b);
87 4b576658 2013-09-23 0intro werrstr("bad root source block");
90 6f4d00ee 2013-09-23 0intro b = blockCopy(b, RootTag, fs->ehi, fs->elo);
91 6f4d00ee 2013-09-23 0intro if(b == nil)
93 6f4d00ee 2013-09-23 0intro localToGlobal(super.active, oscore);
94 6f4d00ee 2013-09-23 0intro super.active = b->addr;
95 6f4d00ee 2013-09-23 0intro bs = cacheLocal(fs->cache, PartSuper, 0, OReadWrite);
96 6f4d00ee 2013-09-23 0intro if(bs == nil){
97 6f4d00ee 2013-09-23 0intro blockPut(b);
98 4b576658 2013-09-23 0intro werrstr("cacheLocal: %r");
101 6f4d00ee 2013-09-23 0intro superPack(&super, bs->data);
102 6f4d00ee 2013-09-23 0intro blockDependency(bs, b, 0, oscore, nil);
103 6f4d00ee 2013-09-23 0intro blockPut(b);
104 6f4d00ee 2013-09-23 0intro blockDirty(bs);
105 6f4d00ee 2013-09-23 0intro blockRemoveLink(bs, globalToLocal(oscore), BtDir, RootTag, 0);
106 6f4d00ee 2013-09-23 0intro blockPut(bs);
107 6f4d00ee 2013-09-23 0intro fs->source = sourceRoot(fs, super.active, mode);
108 6f4d00ee 2013-09-23 0intro if(fs->source == nil){
109 4b576658 2013-09-23 0intro werrstr("sourceRoot: %r");
110 6f4d00ee 2013-09-23 0intro goto Err;
114 6f4d00ee 2013-09-23 0intro //fprint(2, "%s: got fs source\n", argv0);
116 4b576658 2013-09-23 0intro rlock(&fs->elk);
117 6f4d00ee 2013-09-23 0intro fs->file = fileRoot(fs->source);
118 6f4d00ee 2013-09-23 0intro fs->source->file = fs->file; /* point back */
119 4b576658 2013-09-23 0intro runlock(&fs->elk);
120 6f4d00ee 2013-09-23 0intro if(fs->file == nil){
121 4b576658 2013-09-23 0intro werrstr("fileRoot: %r");
122 6f4d00ee 2013-09-23 0intro goto Err;
125 6f4d00ee 2013-09-23 0intro //fprint(2, "%s: got file root\n", argv0);
127 6f4d00ee 2013-09-23 0intro if(mode == OReadWrite){
128 6f4d00ee 2013-09-23 0intro fs->metaFlush = periodicAlloc(fsMetaFlush, fs, 1000);
129 6f4d00ee 2013-09-23 0intro fs->snap = snapInit(fs);
131 6f4d00ee 2013-09-23 0intro return fs;
134 6f4d00ee 2013-09-23 0intro fprint(2, "%s: fsOpen error\n", argv0);
135 6f4d00ee 2013-09-23 0intro fsClose(fs);
136 6f4d00ee 2013-09-23 0intro return nil;
140 6f4d00ee 2013-09-23 0intro fsClose(Fs *fs)
142 4b576658 2013-09-23 0intro rlock(&fs->elk);
143 6f4d00ee 2013-09-23 0intro periodicKill(fs->metaFlush);
144 6f4d00ee 2013-09-23 0intro snapClose(fs->snap);
145 6f4d00ee 2013-09-23 0intro if(fs->file){
146 6f4d00ee 2013-09-23 0intro fileMetaFlush(fs->file, 0);
147 6f4d00ee 2013-09-23 0intro if(!fileDecRef(fs->file))
148 4b576658 2013-09-23 0intro sysfatal("fsClose: files still in use: %r");
150 6f4d00ee 2013-09-23 0intro fs->file = nil;
151 6f4d00ee 2013-09-23 0intro sourceClose(fs->source);
152 6f4d00ee 2013-09-23 0intro cacheFree(fs->cache);
153 6f4d00ee 2013-09-23 0intro if(fs->arch)
154 6f4d00ee 2013-09-23 0intro archFree(fs->arch);
155 4b576658 2013-09-23 0intro vtfree(fs->name);
156 4b576658 2013-09-23 0intro runlock(&fs->elk);
157 6f4d00ee 2013-09-23 0intro memset(fs, ~0, sizeof(Fs));
158 4b576658 2013-09-23 0intro vtfree(fs);
162 6f4d00ee 2013-09-23 0intro fsRedial(Fs *fs, char *host)
164 4b576658 2013-09-23 0intro if(vtredial(fs->z, host) < 0)
165 6f4d00ee 2013-09-23 0intro return 0;
166 4b576658 2013-09-23 0intro if(vtconnect(fs->z) < 0)
167 6f4d00ee 2013-09-23 0intro return 0;
168 6f4d00ee 2013-09-23 0intro return 1;
172 6f4d00ee 2013-09-23 0intro fsGetRoot(Fs *fs)
174 6f4d00ee 2013-09-23 0intro return fileIncRef(fs->file);
178 6f4d00ee 2013-09-23 0intro fsGetBlockSize(Fs *fs)
180 6f4d00ee 2013-09-23 0intro return fs->blockSize;
184 6f4d00ee 2013-09-23 0intro superGet(Cache *c, Super* super)
186 6f4d00ee 2013-09-23 0intro Block *b;
188 6f4d00ee 2013-09-23 0intro if((b = cacheLocal(c, PartSuper, 0, OReadWrite)) == nil){
189 4b576658 2013-09-23 0intro fprint(2, "%s: superGet: cacheLocal failed: %r\n", argv0);
190 6f4d00ee 2013-09-23 0intro return nil;
192 6f4d00ee 2013-09-23 0intro if(!superUnpack(super, b->data)){
193 4b576658 2013-09-23 0intro fprint(2, "%s: superGet: superUnpack failed: %r\n", argv0);
194 6f4d00ee 2013-09-23 0intro blockPut(b);
195 6f4d00ee 2013-09-23 0intro return nil;
198 6f4d00ee 2013-09-23 0intro return b;
202 6f4d00ee 2013-09-23 0intro superWrite(Block* b, Super* super, int forceWrite)
204 6f4d00ee 2013-09-23 0intro superPack(super, b->data);
205 6f4d00ee 2013-09-23 0intro blockDirty(b);
206 6f4d00ee 2013-09-23 0intro if(forceWrite){
207 6f4d00ee 2013-09-23 0intro while(!blockWrite(b, Waitlock)){
208 6f4d00ee 2013-09-23 0intro /* this should no longer happen */
209 6f4d00ee 2013-09-23 0intro fprint(2, "%s: could not write super block; "
210 6f4d00ee 2013-09-23 0intro "waiting 10 seconds\n", argv0);
211 6f4d00ee 2013-09-23 0intro sleep(10*1000);
213 6f4d00ee 2013-09-23 0intro while(b->iostate != BioClean && b->iostate != BioDirty){
214 6f4d00ee 2013-09-23 0intro assert(b->iostate == BioWriting);
215 4b576658 2013-09-23 0intro rsleep(&b->ioready);
218 6f4d00ee 2013-09-23 0intro * it's okay that b might still be dirty.
219 6f4d00ee 2013-09-23 0intro * that means it got written out but with an old root pointer,
220 6f4d00ee 2013-09-23 0intro * but the other fields went out, and those are the ones
221 6f4d00ee 2013-09-23 0intro * we really care about. (specifically, epochHigh; see fsSnapshot).
227 6f4d00ee 2013-09-23 0intro * Prepare the directory to store a snapshot.
228 6f4d00ee 2013-09-23 0intro * Temporary snapshots go into /snapshot/yyyy/mmdd/hhmm[.#]
229 6f4d00ee 2013-09-23 0intro * Archival snapshots go into /archive/yyyy/mmdd[.#].
231 6f4d00ee 2013-09-23 0intro * TODO This should be rewritten to eliminate most of the duplication.
233 6f4d00ee 2013-09-23 0intro static File*
234 6f4d00ee 2013-09-23 0intro fileOpenSnapshot(Fs *fs, char *dstpath, int doarchive)
237 6f4d00ee 2013-09-23 0intro char buf[30], *s, *p, *elem;
238 6f4d00ee 2013-09-23 0intro File *dir, *f;
241 6f4d00ee 2013-09-23 0intro if(dstpath){
242 6f4d00ee 2013-09-23 0intro if((p = strrchr(dstpath, '/')) != nil){
243 6f4d00ee 2013-09-23 0intro *p++ = '\0';
244 6f4d00ee 2013-09-23 0intro elem = p;
245 6f4d00ee 2013-09-23 0intro p = dstpath;
246 6f4d00ee 2013-09-23 0intro if(*p == '\0')
250 6f4d00ee 2013-09-23 0intro elem = dstpath;
252 6f4d00ee 2013-09-23 0intro if((dir = fileOpen(fs, p)) == nil)
253 6f4d00ee 2013-09-23 0intro return nil;
254 6f4d00ee 2013-09-23 0intro f = fileCreate(dir, elem, ModeDir|ModeSnapshot|0555, "adm");
255 6f4d00ee 2013-09-23 0intro fileDecRef(dir);
256 6f4d00ee 2013-09-23 0intro return f;
257 6f4d00ee 2013-09-23 0intro }else if(doarchive){
259 6f4d00ee 2013-09-23 0intro * a snapshot intended to be archived to venti.
261 6f4d00ee 2013-09-23 0intro dir = fileOpen(fs, "/archive");
262 6f4d00ee 2013-09-23 0intro if(dir == nil)
263 6f4d00ee 2013-09-23 0intro return nil;
264 6f4d00ee 2013-09-23 0intro now = *localtime(time(0));
266 6f4d00ee 2013-09-23 0intro /* yyyy */
267 6f4d00ee 2013-09-23 0intro snprint(buf, sizeof(buf), "%d", now.year+1900);
268 6f4d00ee 2013-09-23 0intro f = fileWalk(dir, buf);
269 6f4d00ee 2013-09-23 0intro if(f == nil)
270 6f4d00ee 2013-09-23 0intro f = fileCreate(dir, buf, ModeDir|0555, "adm");
271 6f4d00ee 2013-09-23 0intro fileDecRef(dir);
272 6f4d00ee 2013-09-23 0intro if(f == nil)
273 6f4d00ee 2013-09-23 0intro return nil;
276 6f4d00ee 2013-09-23 0intro /* mmdd[#] */
277 6f4d00ee 2013-09-23 0intro snprint(buf, sizeof(buf), "%02d%02d", now.mon+1, now.mday);
278 6f4d00ee 2013-09-23 0intro s = buf+strlen(buf);
279 6f4d00ee 2013-09-23 0intro for(n=0;; n++){
281 6f4d00ee 2013-09-23 0intro seprint(s, buf+sizeof(buf), ".%d", n);
282 6f4d00ee 2013-09-23 0intro f = fileWalk(dir, buf);
283 6f4d00ee 2013-09-23 0intro if(f != nil){
284 6f4d00ee 2013-09-23 0intro fileDecRef(f);
285 6f4d00ee 2013-09-23 0intro continue;
287 6f4d00ee 2013-09-23 0intro f = fileCreate(dir, buf, ModeDir|ModeSnapshot|0555, "adm");
290 6f4d00ee 2013-09-23 0intro fileDecRef(dir);
291 6f4d00ee 2013-09-23 0intro return f;
294 6f4d00ee 2013-09-23 0intro * Just a temporary snapshot
295 6f4d00ee 2013-09-23 0intro * We'll use /snapshot/yyyy/mmdd/hhmm.
296 6f4d00ee 2013-09-23 0intro * There may well be a better naming scheme.
297 6f4d00ee 2013-09-23 0intro * (I'd have used hh:mm but ':' is reserved in Microsoft file systems.)
299 6f4d00ee 2013-09-23 0intro dir = fileOpen(fs, "/snapshot");
300 6f4d00ee 2013-09-23 0intro if(dir == nil)
301 6f4d00ee 2013-09-23 0intro return nil;
303 6f4d00ee 2013-09-23 0intro now = *localtime(time(0));
305 6f4d00ee 2013-09-23 0intro /* yyyy */
306 6f4d00ee 2013-09-23 0intro snprint(buf, sizeof(buf), "%d", now.year+1900);
307 6f4d00ee 2013-09-23 0intro f = fileWalk(dir, buf);
308 6f4d00ee 2013-09-23 0intro if(f == nil)
309 6f4d00ee 2013-09-23 0intro f = fileCreate(dir, buf, ModeDir|0555, "adm");
310 6f4d00ee 2013-09-23 0intro fileDecRef(dir);
311 6f4d00ee 2013-09-23 0intro if(f == nil)
312 6f4d00ee 2013-09-23 0intro return nil;
315 6f4d00ee 2013-09-23 0intro /* mmdd */
316 6f4d00ee 2013-09-23 0intro snprint(buf, sizeof(buf), "%02d%02d", now.mon+1, now.mday);
317 6f4d00ee 2013-09-23 0intro f = fileWalk(dir, buf);
318 6f4d00ee 2013-09-23 0intro if(f == nil)
319 6f4d00ee 2013-09-23 0intro f = fileCreate(dir, buf, ModeDir|0555, "adm");
320 6f4d00ee 2013-09-23 0intro fileDecRef(dir);
321 6f4d00ee 2013-09-23 0intro if(f == nil)
322 6f4d00ee 2013-09-23 0intro return nil;
325 6f4d00ee 2013-09-23 0intro /* hhmm[.#] */
326 6f4d00ee 2013-09-23 0intro snprint(buf, sizeof buf, "%02d%02d", now.hour, now.min);
327 6f4d00ee 2013-09-23 0intro s = buf+strlen(buf);
328 6f4d00ee 2013-09-23 0intro for(n=0;; n++){
330 6f4d00ee 2013-09-23 0intro seprint(s, buf+sizeof(buf), ".%d", n);
331 6f4d00ee 2013-09-23 0intro f = fileWalk(dir, buf);
332 6f4d00ee 2013-09-23 0intro if(f != nil){
333 6f4d00ee 2013-09-23 0intro fileDecRef(f);
334 6f4d00ee 2013-09-23 0intro continue;
336 6f4d00ee 2013-09-23 0intro f = fileCreate(dir, buf, ModeDir|ModeSnapshot|0555, "adm");
339 6f4d00ee 2013-09-23 0intro fileDecRef(dir);
340 6f4d00ee 2013-09-23 0intro return f;
344 6f4d00ee 2013-09-23 0intro static int
345 6f4d00ee 2013-09-23 0intro fsNeedArch(Fs *fs, uint archMinute)
347 6f4d00ee 2013-09-23 0intro int need;
349 6f4d00ee 2013-09-23 0intro char buf[100];
351 6f4d00ee 2013-09-23 0intro ulong then;
353 6f4d00ee 2013-09-23 0intro then = time(0);
354 6f4d00ee 2013-09-23 0intro now = *localtime(then);
356 6f4d00ee 2013-09-23 0intro /* back up to yesterday if necessary */
357 6f4d00ee 2013-09-23 0intro if(now.hour < archMinute/60
358 6f4d00ee 2013-09-23 0intro || now.hour == archMinute/60 && now.min < archMinute%60)
359 6f4d00ee 2013-09-23 0intro now = *localtime(then-86400);
361 6f4d00ee 2013-09-23 0intro snprint(buf, sizeof buf, "/archive/%d/%02d%02d",
362 6f4d00ee 2013-09-23 0intro now.year+1900, now.mon+1, now.mday);
363 6f4d00ee 2013-09-23 0intro need = 1;
364 4b576658 2013-09-23 0intro rlock(&fs->elk);
365 6f4d00ee 2013-09-23 0intro f = fileOpen(fs, buf);
367 6f4d00ee 2013-09-23 0intro need = 0;
368 6f4d00ee 2013-09-23 0intro fileDecRef(f);
370 4b576658 2013-09-23 0intro runlock(&fs->elk);
371 6f4d00ee 2013-09-23 0intro return need;
375 6f4d00ee 2013-09-23 0intro fsEpochLow(Fs *fs, u32int low)
377 6f4d00ee 2013-09-23 0intro Block *bs;
378 6f4d00ee 2013-09-23 0intro Super super;
380 4b576658 2013-09-23 0intro wlock(&fs->elk);
381 6f4d00ee 2013-09-23 0intro if(low > fs->ehi){
382 4b576658 2013-09-23 0intro werrstr("bad low epoch (must be <= %ud)", fs->ehi);
383 4b576658 2013-09-23 0intro wunlock(&fs->elk);
384 6f4d00ee 2013-09-23 0intro return 0;
387 6f4d00ee 2013-09-23 0intro if((bs = superGet(fs->cache, &super)) == nil){
388 4b576658 2013-09-23 0intro wunlock(&fs->elk);
389 6f4d00ee 2013-09-23 0intro return 0;
392 6f4d00ee 2013-09-23 0intro super.epochLow = low;
393 6f4d00ee 2013-09-23 0intro fs->elo = low;
394 6f4d00ee 2013-09-23 0intro superWrite(bs, &super, 1);
395 6f4d00ee 2013-09-23 0intro blockPut(bs);
396 4b576658 2013-09-23 0intro wunlock(&fs->elk);
398 6f4d00ee 2013-09-23 0intro return 1;
401 6f4d00ee 2013-09-23 0intro static int
402 6f4d00ee 2013-09-23 0intro bumpEpoch(Fs *fs, int doarchive)
404 6f4d00ee 2013-09-23 0intro uchar oscore[VtScoreSize];
405 6f4d00ee 2013-09-23 0intro u32int oldaddr;
406 6f4d00ee 2013-09-23 0intro Block *b, *bs;
408 6f4d00ee 2013-09-23 0intro Source *r;
409 6f4d00ee 2013-09-23 0intro Super super;
412 6f4d00ee 2013-09-23 0intro * Duplicate the root block.
414 6f4d00ee 2013-09-23 0intro * As a hint to flchk, the garbage collector,
415 6f4d00ee 2013-09-23 0intro * and any (human) debuggers, store a pointer
416 6f4d00ee 2013-09-23 0intro * to the old root block in entry 1 of the new root block.
418 6f4d00ee 2013-09-23 0intro r = fs->source;
419 6f4d00ee 2013-09-23 0intro b = cacheGlobal(fs->cache, r->score, BtDir, RootTag, OReadOnly);
420 6f4d00ee 2013-09-23 0intro if(b == nil)
421 6f4d00ee 2013-09-23 0intro return 0;
423 6f4d00ee 2013-09-23 0intro memset(&e, 0, sizeof e);
424 4b576658 2013-09-23 0intro e.flags = VtEntryActive | VtEntryLocal | _VtEntryDir;
425 6f4d00ee 2013-09-23 0intro memmove(e.score, b->score, VtScoreSize);
426 6f4d00ee 2013-09-23 0intro e.tag = RootTag;
427 6f4d00ee 2013-09-23 0intro e.snap = b->l.epoch;
429 6f4d00ee 2013-09-23 0intro b = blockCopy(b, RootTag, fs->ehi+1, fs->elo);
430 6f4d00ee 2013-09-23 0intro if(b == nil){
431 4b576658 2013-09-23 0intro fprint(2, "%s: bumpEpoch: blockCopy: %r\n", argv0);
432 6f4d00ee 2013-09-23 0intro return 0;
435 6f4d00ee 2013-09-23 0intro if(0) fprint(2, "%s: snapshot root from %d to %d\n", argv0, oldaddr, b->addr);
436 6f4d00ee 2013-09-23 0intro entryPack(&e, b->data, 1);
437 6f4d00ee 2013-09-23 0intro blockDirty(b);
440 6f4d00ee 2013-09-23 0intro * Update the superblock with the new root and epoch.
442 6f4d00ee 2013-09-23 0intro if((bs = superGet(fs->cache, &super)) == nil)
443 6f4d00ee 2013-09-23 0intro return 0;
445 6f4d00ee 2013-09-23 0intro fs->ehi++;
446 6f4d00ee 2013-09-23 0intro memmove(r->score, b->score, VtScoreSize);
447 6f4d00ee 2013-09-23 0intro r->epoch = fs->ehi;
449 6f4d00ee 2013-09-23 0intro super.epochHigh = fs->ehi;
450 6f4d00ee 2013-09-23 0intro oldaddr = super.active;
451 6f4d00ee 2013-09-23 0intro super.active = b->addr;
452 6f4d00ee 2013-09-23 0intro if(doarchive)
453 6f4d00ee 2013-09-23 0intro super.next = oldaddr;
456 6f4d00ee 2013-09-23 0intro * Record that the new super.active can't get written out until
457 6f4d00ee 2013-09-23 0intro * the new b gets written out. Until then, use the old value.
459 6f4d00ee 2013-09-23 0intro localToGlobal(oldaddr, oscore);
460 6f4d00ee 2013-09-23 0intro blockDependency(bs, b, 0, oscore, nil);
461 6f4d00ee 2013-09-23 0intro blockPut(b);
464 6f4d00ee 2013-09-23 0intro * We force the super block to disk so that super.epochHigh gets updated.
465 6f4d00ee 2013-09-23 0intro * Otherwise, if we crash and come back, we might incorrectly treat as active
466 6f4d00ee 2013-09-23 0intro * some of the blocks that making up the snapshot we just created.
467 6f4d00ee 2013-09-23 0intro * Basically every block in the active file system and all the blocks in
468 6f4d00ee 2013-09-23 0intro * the recently-created snapshot depend on the super block now.
469 6f4d00ee 2013-09-23 0intro * Rather than record all those dependencies, we just force the block to disk.
471 6f4d00ee 2013-09-23 0intro * Note that blockWrite might actually (will probably) send a slightly outdated
472 6f4d00ee 2013-09-23 0intro * super.active to disk. It will be the address of the most recent root that has
473 6f4d00ee 2013-09-23 0intro * gone to disk.
475 6f4d00ee 2013-09-23 0intro superWrite(bs, &super, 1);
476 6f4d00ee 2013-09-23 0intro blockRemoveLink(bs, globalToLocal(oscore), BtDir, RootTag, 0);
477 6f4d00ee 2013-09-23 0intro blockPut(bs);
479 6f4d00ee 2013-09-23 0intro return 1;
483 6f4d00ee 2013-09-23 0intro saveQid(Fs *fs)
485 6f4d00ee 2013-09-23 0intro Block *b;
486 6f4d00ee 2013-09-23 0intro Super super;
487 6f4d00ee 2013-09-23 0intro u64int qidMax;
489 6f4d00ee 2013-09-23 0intro if((b = superGet(fs->cache, &super)) == nil)
490 6f4d00ee 2013-09-23 0intro return 0;
491 6f4d00ee 2013-09-23 0intro qidMax = super.qid;
492 6f4d00ee 2013-09-23 0intro blockPut(b);
494 6f4d00ee 2013-09-23 0intro if(!fileSetQidSpace(fs->file, 0, qidMax))
495 6f4d00ee 2013-09-23 0intro return 0;
497 6f4d00ee 2013-09-23 0intro return 1;
501 6f4d00ee 2013-09-23 0intro fsSnapshot(Fs *fs, char *srcpath, char *dstpath, int doarchive)
503 6f4d00ee 2013-09-23 0intro File *src, *dst;
505 6f4d00ee 2013-09-23 0intro assert(fs->mode == OReadWrite);
507 6f4d00ee 2013-09-23 0intro dst = nil;
509 6f4d00ee 2013-09-23 0intro if(fs->halted){
510 4b576658 2013-09-23 0intro werrstr("file system is halted");
511 6f4d00ee 2013-09-23 0intro return 0;
515 6f4d00ee 2013-09-23 0intro * Freeze file system activity.
517 4b576658 2013-09-23 0intro wlock(&fs->elk);
520 6f4d00ee 2013-09-23 0intro * Get the root of the directory we're going to save.
522 6f4d00ee 2013-09-23 0intro if(srcpath == nil)
523 6f4d00ee 2013-09-23 0intro srcpath = "/active";
524 6f4d00ee 2013-09-23 0intro src = fileOpen(fs, srcpath);
525 6f4d00ee 2013-09-23 0intro if(src == nil)
526 6f4d00ee 2013-09-23 0intro goto Err;
529 6f4d00ee 2013-09-23 0intro * It is important that we maintain the invariant that:
530 6f4d00ee 2013-09-23 0intro * if both b and bb are marked as Active with start epoch e
531 6f4d00ee 2013-09-23 0intro * and b points at bb, then no other pointers to bb exist.
533 6f4d00ee 2013-09-23 0intro * When bb is unlinked from b, its close epoch is set to b's epoch.
534 6f4d00ee 2013-09-23 0intro * A block with epoch == close epoch is
535 6f4d00ee 2013-09-23 0intro * treated as free by cacheAllocBlock; this aggressively
536 6f4d00ee 2013-09-23 0intro * reclaims blocks after they have been stored to Venti.
538 6f4d00ee 2013-09-23 0intro * Let's say src->source is block sb, and src->msource is block
539 6f4d00ee 2013-09-23 0intro * mb. Let's also say that block b holds the Entry structures for
540 6f4d00ee 2013-09-23 0intro * both src->source and src->msource (their Entry structures might
541 6f4d00ee 2013-09-23 0intro * be in different blocks, but the argument is the same).
542 6f4d00ee 2013-09-23 0intro * That is, right now we have:
544 6f4d00ee 2013-09-23 0intro * b Active w/ epoch e, holds ptrs to sb and mb.
545 6f4d00ee 2013-09-23 0intro * sb Active w/ epoch e.
546 6f4d00ee 2013-09-23 0intro * mb Active w/ epoch e.
548 6f4d00ee 2013-09-23 0intro * With things as they are now, the invariant requires that
549 6f4d00ee 2013-09-23 0intro * b holds the only pointers to sb and mb. We want to record
550 6f4d00ee 2013-09-23 0intro * pointers to sb and mb in new Entries corresponding to dst,
551 6f4d00ee 2013-09-23 0intro * which breaks the invariant. Thus we need to do something
552 6f4d00ee 2013-09-23 0intro * about b. Specifically, we bump the file system's epoch and
553 6f4d00ee 2013-09-23 0intro * then rewalk the path from the root down to and including b.
554 6f4d00ee 2013-09-23 0intro * This will copy-on-write as we walk, so now the state will be:
556 6f4d00ee 2013-09-23 0intro * b Snap w/ epoch e, holds ptrs to sb and mb.
557 6f4d00ee 2013-09-23 0intro * new-b Active w/ epoch e+1, holds ptrs to sb and mb.
558 6f4d00ee 2013-09-23 0intro * sb Active w/ epoch e.
559 6f4d00ee 2013-09-23 0intro * mb Active w/ epoch e.
561 6f4d00ee 2013-09-23 0intro * In this state, it's perfectly okay to make more pointers to sb and mb.
563 6f4d00ee 2013-09-23 0intro if(!bumpEpoch(fs, 0) || !fileWalkSources(src))
564 6f4d00ee 2013-09-23 0intro goto Err;
567 6f4d00ee 2013-09-23 0intro * Sync to disk. I'm not sure this is necessary, but better safe than sorry.
569 6f4d00ee 2013-09-23 0intro cacheFlush(fs->cache, 1);
572 6f4d00ee 2013-09-23 0intro * Create the directory where we will store the copy of src.
574 6f4d00ee 2013-09-23 0intro dst = fileOpenSnapshot(fs, dstpath, doarchive);
575 6f4d00ee 2013-09-23 0intro if(dst == nil)
576 6f4d00ee 2013-09-23 0intro goto Err;
579 6f4d00ee 2013-09-23 0intro * Actually make the copy by setting dst's source and msource
580 6f4d00ee 2013-09-23 0intro * to be src's.
582 6f4d00ee 2013-09-23 0intro if(!fileSnapshot(dst, src, fs->ehi-1, doarchive))
583 6f4d00ee 2013-09-23 0intro goto Err;
585 6f4d00ee 2013-09-23 0intro fileDecRef(src);
586 6f4d00ee 2013-09-23 0intro fileDecRef(dst);
587 6f4d00ee 2013-09-23 0intro src = nil;
588 6f4d00ee 2013-09-23 0intro dst = nil;
591 6f4d00ee 2013-09-23 0intro * Make another copy of the file system. This one is for the
592 6f4d00ee 2013-09-23 0intro * archiver, so that the file system we archive has the recently
593 6f4d00ee 2013-09-23 0intro * added snapshot both in /active and in /archive/yyyy/mmdd[.#].
595 6f4d00ee 2013-09-23 0intro if(doarchive){
596 6f4d00ee 2013-09-23 0intro if(!saveQid(fs))
597 6f4d00ee 2013-09-23 0intro goto Err;
598 6f4d00ee 2013-09-23 0intro if(!bumpEpoch(fs, 1))
599 6f4d00ee 2013-09-23 0intro goto Err;
602 4b576658 2013-09-23 0intro wunlock(&fs->elk);
604 6f4d00ee 2013-09-23 0intro /* BUG? can fs->arch fall out from under us here? */
605 6f4d00ee 2013-09-23 0intro if(doarchive && fs->arch)
606 6f4d00ee 2013-09-23 0intro archKick(fs->arch);
608 6f4d00ee 2013-09-23 0intro return 1;
611 4b576658 2013-09-23 0intro fprint(2, "%s: fsSnapshot: %r\n", argv0);
613 6f4d00ee 2013-09-23 0intro fileDecRef(src);
615 6f4d00ee 2013-09-23 0intro fileDecRef(dst);
616 4b576658 2013-09-23 0intro wunlock(&fs->elk);
617 6f4d00ee 2013-09-23 0intro return 0;
621 6f4d00ee 2013-09-23 0intro fsVac(Fs *fs, char *name, uchar score[VtScoreSize])
624 6f4d00ee 2013-09-23 0intro DirEntry de;
625 6f4d00ee 2013-09-23 0intro Entry e, ee;
628 4b576658 2013-09-23 0intro rlock(&fs->elk);
629 6f4d00ee 2013-09-23 0intro f = fileOpen(fs, name);
630 6f4d00ee 2013-09-23 0intro if(f == nil){
631 4b576658 2013-09-23 0intro runlock(&fs->elk);
632 6f4d00ee 2013-09-23 0intro return 0;
635 6f4d00ee 2013-09-23 0intro if(!fileGetSources(f, &e, &ee) || !fileGetDir(f, &de)){
636 6f4d00ee 2013-09-23 0intro fileDecRef(f);
637 4b576658 2013-09-23 0intro runlock(&fs->elk);
638 6f4d00ee 2013-09-23 0intro return 0;
640 6f4d00ee 2013-09-23 0intro fileDecRef(f);
642 6f4d00ee 2013-09-23 0intro r = mkVac(fs->z, fs->blockSize, &e, &ee, &de, score);
643 4b576658 2013-09-23 0intro runlock(&fs->elk);
644 6f4d00ee 2013-09-23 0intro return r;
647 6f4d00ee 2013-09-23 0intro static int
648 4b576658 2013-09-23 0intro vtWriteBlock(VtConn *z, uchar *buf, uint n, uint type, uchar score[VtScoreSize])
650 4b576658 2013-09-23 0intro if(vtwrite(z, score, type, buf, n) < 0)
651 6f4d00ee 2013-09-23 0intro return 0;
652 4b576658 2013-09-23 0intro if(vtsha1check(score, buf, n) < 0)
653 6f4d00ee 2013-09-23 0intro return 0;
654 6f4d00ee 2013-09-23 0intro return 1;
658 4b576658 2013-09-23 0intro mkVac(VtConn *z, uint blockSize, Entry *pe, Entry *pee, DirEntry *pde, uchar score[VtScoreSize])
660 6f4d00ee 2013-09-23 0intro uchar buf[8192];
662 6f4d00ee 2013-09-23 0intro uchar *p;
664 6f4d00ee 2013-09-23 0intro DirEntry de;
665 6f4d00ee 2013-09-23 0intro Entry e, ee, eee;
666 6f4d00ee 2013-09-23 0intro MetaBlock mb;
667 6f4d00ee 2013-09-23 0intro MetaEntry me;
668 6f4d00ee 2013-09-23 0intro VtRoot root;
671 6f4d00ee 2013-09-23 0intro ee = *pee;
672 6f4d00ee 2013-09-23 0intro de = *pde;
674 6f4d00ee 2013-09-23 0intro if(globalToLocal(e.score) != NilBlock
675 6f4d00ee 2013-09-23 0intro || (ee.flags&VtEntryActive && globalToLocal(ee.score) != NilBlock)){
676 4b576658 2013-09-23 0intro werrstr("can only vac paths already stored on venti");
677 6f4d00ee 2013-09-23 0intro return 0;
681 6f4d00ee 2013-09-23 0intro * Build metadata source for root.
683 6f4d00ee 2013-09-23 0intro n = deSize(&de);
684 6f4d00ee 2013-09-23 0intro if(n+MetaHeaderSize+MetaIndexSize > sizeof buf){
685 4b576658 2013-09-23 0intro werrstr("DirEntry too big");
686 6f4d00ee 2013-09-23 0intro return 0;
688 6f4d00ee 2013-09-23 0intro memset(buf, 0, sizeof buf);
689 6f4d00ee 2013-09-23 0intro mbInit(&mb, buf, n+MetaHeaderSize+MetaIndexSize, 1);
690 6f4d00ee 2013-09-23 0intro p = mbAlloc(&mb, n);
691 6f4d00ee 2013-09-23 0intro if(p == nil)
693 6f4d00ee 2013-09-23 0intro mbSearch(&mb, de.elem, &i, &me);
694 6f4d00ee 2013-09-23 0intro assert(me.p == nil);
695 6f4d00ee 2013-09-23 0intro me.p = p;
696 6f4d00ee 2013-09-23 0intro me.size = n;
697 6f4d00ee 2013-09-23 0intro dePack(&de, &me);
698 6f4d00ee 2013-09-23 0intro mbInsert(&mb, i, &me);
699 6f4d00ee 2013-09-23 0intro mbPack(&mb);
701 6f4d00ee 2013-09-23 0intro eee.size = n+MetaHeaderSize+MetaIndexSize;
702 6f4d00ee 2013-09-23 0intro if(!vtWriteBlock(z, buf, eee.size, VtDataType, eee.score))
703 6f4d00ee 2013-09-23 0intro return 0;
704 6f4d00ee 2013-09-23 0intro eee.psize = 8192;
705 6f4d00ee 2013-09-23 0intro eee.dsize = 8192;
706 6f4d00ee 2013-09-23 0intro eee.depth = 0;
707 6f4d00ee 2013-09-23 0intro eee.flags = VtEntryActive;
710 6f4d00ee 2013-09-23 0intro * Build root source with three entries in it.
712 6f4d00ee 2013-09-23 0intro entryPack(&e, buf, 0);
713 6f4d00ee 2013-09-23 0intro entryPack(&ee, buf, 1);
714 6f4d00ee 2013-09-23 0intro entryPack(&eee, buf, 2);
716 6f4d00ee 2013-09-23 0intro n = VtEntrySize*3;
717 6f4d00ee 2013-09-23 0intro memset(&root, 0, sizeof root);
718 6f4d00ee 2013-09-23 0intro if(!vtWriteBlock(z, buf, n, VtDirType, root.score))
719 6f4d00ee 2013-09-23 0intro return 0;
722 6f4d00ee 2013-09-23 0intro * Save root.
724 6f4d00ee 2013-09-23 0intro strecpy(root.type, root.type+sizeof root.type, "vac");
725 6f4d00ee 2013-09-23 0intro strecpy(root.name, root.name+sizeof root.name, de.elem);
726 4b576658 2013-09-23 0intro root.blocksize = blockSize;
727 4b576658 2013-09-23 0intro vtrootpack(&root, buf);
728 6f4d00ee 2013-09-23 0intro if(!vtWriteBlock(z, buf, VtRootSize, VtRootType, score))
729 6f4d00ee 2013-09-23 0intro return 0;
731 6f4d00ee 2013-09-23 0intro return 1;
735 6f4d00ee 2013-09-23 0intro fsSync(Fs *fs)
737 4b576658 2013-09-23 0intro wlock(&fs->elk);
738 6f4d00ee 2013-09-23 0intro fileMetaFlush(fs->file, 1);
739 6f4d00ee 2013-09-23 0intro cacheFlush(fs->cache, 1);
740 4b576658 2013-09-23 0intro wunlock(&fs->elk);
741 6f4d00ee 2013-09-23 0intro return 1;
745 6f4d00ee 2013-09-23 0intro fsHalt(Fs *fs)
747 4b576658 2013-09-23 0intro wlock(&fs->elk);
748 6f4d00ee 2013-09-23 0intro fs->halted = 1;
749 6f4d00ee 2013-09-23 0intro fileMetaFlush(fs->file, 1);
750 6f4d00ee 2013-09-23 0intro cacheFlush(fs->cache, 1);
751 6f4d00ee 2013-09-23 0intro return 1;
755 6f4d00ee 2013-09-23 0intro fsUnhalt(Fs *fs)
757 6f4d00ee 2013-09-23 0intro if(!fs->halted)
758 6f4d00ee 2013-09-23 0intro return 0;
759 6f4d00ee 2013-09-23 0intro fs->halted = 0;
760 4b576658 2013-09-23 0intro wunlock(&fs->elk);
761 6f4d00ee 2013-09-23 0intro return 1;
765 6f4d00ee 2013-09-23 0intro fsNextQid(Fs *fs, u64int *qid)
767 6f4d00ee 2013-09-23 0intro Block *b;
768 6f4d00ee 2013-09-23 0intro Super super;
770 6f4d00ee 2013-09-23 0intro if((b = superGet(fs->cache, &super)) == nil)
771 6f4d00ee 2013-09-23 0intro return 0;
773 6f4d00ee 2013-09-23 0intro *qid = super.qid++;
776 6f4d00ee 2013-09-23 0intro * It's okay if the super block doesn't go to disk immediately,
777 6f4d00ee 2013-09-23 0intro * since fileMetaAlloc will record a dependency between the
778 6f4d00ee 2013-09-23 0intro * block holding this qid and the super block. See file.c:/^fileMetaAlloc.
780 6f4d00ee 2013-09-23 0intro superWrite(b, &super, 0);
781 6f4d00ee 2013-09-23 0intro blockPut(b);
782 6f4d00ee 2013-09-23 0intro return 1;
785 6f4d00ee 2013-09-23 0intro static void
786 6f4d00ee 2013-09-23 0intro fsMetaFlush(void *a)
789 6f4d00ee 2013-09-23 0intro Fs *fs = a;
791 4b576658 2013-09-23 0intro rlock(&fs->elk);
792 6f4d00ee 2013-09-23 0intro rv = fileMetaFlush(fs->file, 1);
793 4b576658 2013-09-23 0intro runlock(&fs->elk);
794 6f4d00ee 2013-09-23 0intro if(rv > 0)
795 6f4d00ee 2013-09-23 0intro cacheFlush(fs->cache, 0);
798 6f4d00ee 2013-09-23 0intro static int
799 6f4d00ee 2013-09-23 0intro fsEsearch1(File *f, char *path, u32int savetime, u32int *plo)
801 6f4d00ee 2013-09-23 0intro int n, r;
802 6f4d00ee 2013-09-23 0intro DirEntry de;
803 6f4d00ee 2013-09-23 0intro DirEntryEnum *dee;
804 6f4d00ee 2013-09-23 0intro File *ff;
805 6f4d00ee 2013-09-23 0intro Entry e, ee;
808 6f4d00ee 2013-09-23 0intro dee = deeOpen(f);
809 6f4d00ee 2013-09-23 0intro if(dee == nil)
810 6f4d00ee 2013-09-23 0intro return 0;
814 6f4d00ee 2013-09-23 0intro r = deeRead(dee, &de);
815 6f4d00ee 2013-09-23 0intro if(r <= 0)
817 6f4d00ee 2013-09-23 0intro if(de.mode & ModeSnapshot){
818 6f4d00ee 2013-09-23 0intro if((ff = fileWalk(f, de.elem)) != nil){
819 6f4d00ee 2013-09-23 0intro if(fileGetSources(ff, &e, &ee))
820 6f4d00ee 2013-09-23 0intro if(de.mtime >= savetime && e.snap != 0)
821 6f4d00ee 2013-09-23 0intro if(e.snap < *plo)
822 6f4d00ee 2013-09-23 0intro *plo = e.snap;
823 6f4d00ee 2013-09-23 0intro fileDecRef(ff);
826 6f4d00ee 2013-09-23 0intro else if(de.mode & ModeDir){
827 6f4d00ee 2013-09-23 0intro if((ff = fileWalk(f, de.elem)) != nil){
828 6f4d00ee 2013-09-23 0intro t = smprint("%s/%s", path, de.elem);
829 6f4d00ee 2013-09-23 0intro n += fsEsearch1(ff, t, savetime, plo);
830 4b576658 2013-09-23 0intro vtfree(t);
831 6f4d00ee 2013-09-23 0intro fileDecRef(ff);
834 6f4d00ee 2013-09-23 0intro deCleanup(&de);
835 6f4d00ee 2013-09-23 0intro if(r < 0)
838 6f4d00ee 2013-09-23 0intro deeClose(dee);
840 6f4d00ee 2013-09-23 0intro return n;
843 6f4d00ee 2013-09-23 0intro static int
844 6f4d00ee 2013-09-23 0intro fsEsearch(Fs *fs, char *path, u32int savetime, u32int *plo)
848 6f4d00ee 2013-09-23 0intro DirEntry de;
850 6f4d00ee 2013-09-23 0intro f = fileOpen(fs, path);
851 6f4d00ee 2013-09-23 0intro if(f == nil)
852 6f4d00ee 2013-09-23 0intro return 0;
853 6f4d00ee 2013-09-23 0intro if(!fileGetDir(f, &de)){
854 6f4d00ee 2013-09-23 0intro fileDecRef(f);
855 6f4d00ee 2013-09-23 0intro return 0;
857 6f4d00ee 2013-09-23 0intro if((de.mode & ModeDir) == 0){
858 6f4d00ee 2013-09-23 0intro fileDecRef(f);
859 6f4d00ee 2013-09-23 0intro deCleanup(&de);
860 6f4d00ee 2013-09-23 0intro return 0;
862 6f4d00ee 2013-09-23 0intro deCleanup(&de);
863 6f4d00ee 2013-09-23 0intro n = fsEsearch1(f, path, savetime, plo);
864 6f4d00ee 2013-09-23 0intro fileDecRef(f);
865 6f4d00ee 2013-09-23 0intro return n;
869 6f4d00ee 2013-09-23 0intro fsSnapshotCleanup(Fs *fs, u32int age)
871 6f4d00ee 2013-09-23 0intro u32int lo;
874 6f4d00ee 2013-09-23 0intro * Find the best low epoch we can use,
875 6f4d00ee 2013-09-23 0intro * given that we need to save all the unventied archives
876 6f4d00ee 2013-09-23 0intro * and all the snapshots younger than age.
878 4b576658 2013-09-23 0intro rlock(&fs->elk);
879 6f4d00ee 2013-09-23 0intro lo = fs->ehi;
880 6f4d00ee 2013-09-23 0intro fsEsearch(fs, "/archive", 0, &lo);
881 6f4d00ee 2013-09-23 0intro fsEsearch(fs, "/snapshot", time(0)-age*60, &lo);
882 4b576658 2013-09-23 0intro runlock(&fs->elk);
884 6f4d00ee 2013-09-23 0intro fsEpochLow(fs, lo);
885 6f4d00ee 2013-09-23 0intro fsSnapshotRemove(fs);
888 6f4d00ee 2013-09-23 0intro /* remove all snapshots that have expired */
889 6f4d00ee 2013-09-23 0intro /* return number of directory entries remaining */
890 6f4d00ee 2013-09-23 0intro static int
891 6f4d00ee 2013-09-23 0intro fsRsearch1(File *f, char *s)
893 6f4d00ee 2013-09-23 0intro int n, r;
894 6f4d00ee 2013-09-23 0intro DirEntry de;
895 6f4d00ee 2013-09-23 0intro DirEntryEnum *dee;
896 6f4d00ee 2013-09-23 0intro File *ff;
897 4b576658 2013-09-23 0intro char *t, e[ERRMAX];
899 6f4d00ee 2013-09-23 0intro dee = deeOpen(f);
900 6f4d00ee 2013-09-23 0intro if(dee == nil)
901 6f4d00ee 2013-09-23 0intro return 0;
905 6f4d00ee 2013-09-23 0intro r = deeRead(dee, &de);
906 6f4d00ee 2013-09-23 0intro if(r <= 0)
909 6f4d00ee 2013-09-23 0intro if(de.mode & ModeSnapshot){
910 4b576658 2013-09-23 0intro rerrstr(e, sizeof e);
911 6f4d00ee 2013-09-23 0intro if((ff = fileWalk(f, de.elem)) != nil)
912 6f4d00ee 2013-09-23 0intro fileDecRef(ff);
913 4b576658 2013-09-23 0intro else if(strcmp(e, ESnapOld) == 0){
914 6f4d00ee 2013-09-23 0intro if(fileClri(f, de.elem, "adm"))
918 6f4d00ee 2013-09-23 0intro else if(de.mode & ModeDir){
919 6f4d00ee 2013-09-23 0intro if((ff = fileWalk(f, de.elem)) != nil){
920 6f4d00ee 2013-09-23 0intro t = smprint("%s/%s", s, de.elem);
921 6f4d00ee 2013-09-23 0intro if(fsRsearch1(ff, t) == 0)
922 6f4d00ee 2013-09-23 0intro if(fileRemove(ff, "adm"))
924 4b576658 2013-09-23 0intro vtfree(t);
925 6f4d00ee 2013-09-23 0intro fileDecRef(ff);
928 6f4d00ee 2013-09-23 0intro deCleanup(&de);
929 6f4d00ee 2013-09-23 0intro if(r < 0)
932 6f4d00ee 2013-09-23 0intro deeClose(dee);
934 6f4d00ee 2013-09-23 0intro return n;
937 6f4d00ee 2013-09-23 0intro static int
938 6f4d00ee 2013-09-23 0intro fsRsearch(Fs *fs, char *path)
941 6f4d00ee 2013-09-23 0intro DirEntry de;
943 6f4d00ee 2013-09-23 0intro f = fileOpen(fs, path);
944 6f4d00ee 2013-09-23 0intro if(f == nil)
945 6f4d00ee 2013-09-23 0intro return 0;
946 6f4d00ee 2013-09-23 0intro if(!fileGetDir(f, &de)){
947 6f4d00ee 2013-09-23 0intro fileDecRef(f);
948 6f4d00ee 2013-09-23 0intro return 0;
950 6f4d00ee 2013-09-23 0intro if((de.mode & ModeDir) == 0){
951 6f4d00ee 2013-09-23 0intro fileDecRef(f);
952 6f4d00ee 2013-09-23 0intro deCleanup(&de);
953 6f4d00ee 2013-09-23 0intro return 0;
955 6f4d00ee 2013-09-23 0intro deCleanup(&de);
956 6f4d00ee 2013-09-23 0intro fsRsearch1(f, path);
957 6f4d00ee 2013-09-23 0intro fileDecRef(f);
958 6f4d00ee 2013-09-23 0intro return 1;
962 6f4d00ee 2013-09-23 0intro fsSnapshotRemove(Fs *fs)
964 4b576658 2013-09-23 0intro rlock(&fs->elk);
965 6f4d00ee 2013-09-23 0intro fsRsearch(fs, "/snapshot");
966 4b576658 2013-09-23 0intro runlock(&fs->elk);
969 6f4d00ee 2013-09-23 0intro struct Snap
972 6f4d00ee 2013-09-23 0intro Periodic*tick;
973 4b576658 2013-09-23 0intro QLock lk;
974 6f4d00ee 2013-09-23 0intro uint snapMinutes;
975 6f4d00ee 2013-09-23 0intro uint archMinute;
976 6f4d00ee 2013-09-23 0intro uint snapLife;
977 6f4d00ee 2013-09-23 0intro u32int lastSnap;
978 6f4d00ee 2013-09-23 0intro u32int lastArch;
979 6f4d00ee 2013-09-23 0intro u32int lastCleanup;
980 6f4d00ee 2013-09-23 0intro uint ignore;
983 6f4d00ee 2013-09-23 0intro static void
984 6f4d00ee 2013-09-23 0intro snapEvent(void *v)
987 6f4d00ee 2013-09-23 0intro u32int now, min;
989 6f4d00ee 2013-09-23 0intro int need;
990 6f4d00ee 2013-09-23 0intro u32int snaplife;
994 6f4d00ee 2013-09-23 0intro now = time(0)/60;
995 4b576658 2013-09-23 0intro qlock(&s->lk);
998 6f4d00ee 2013-09-23 0intro * Snapshots happen every snapMinutes minutes.
999 6f4d00ee 2013-09-23 0intro * If we miss a snapshot (for example, because we
1000 6f4d00ee 2013-09-23 0intro * were down), we wait for the next one.
1002 6f4d00ee 2013-09-23 0intro if(s->snapMinutes != ~0 && s->snapMinutes != 0
1003 6f4d00ee 2013-09-23 0intro && now%s->snapMinutes==0 && now != s->lastSnap){
1004 6f4d00ee 2013-09-23 0intro if(!fsSnapshot(s->fs, nil, nil, 0))
1005 4b576658 2013-09-23 0intro fprint(2, "%s: fsSnapshot snap: %r\n", argv0);
1006 6f4d00ee 2013-09-23 0intro s->lastSnap = now;
1010 6f4d00ee 2013-09-23 0intro * Archival snapshots happen at archMinute.
1011 6f4d00ee 2013-09-23 0intro * If we miss an archive (for example, because we
1012 6f4d00ee 2013-09-23 0intro * were down), we do it as soon as possible.
1014 6f4d00ee 2013-09-23 0intro tm = *localtime(now*60);
1015 6f4d00ee 2013-09-23 0intro min = tm.hour*60+tm.min;
1016 6f4d00ee 2013-09-23 0intro if(s->archMinute != ~0){
1017 6f4d00ee 2013-09-23 0intro need = 0;
1018 6f4d00ee 2013-09-23 0intro if(min == s->archMinute && now != s->lastArch)
1019 6f4d00ee 2013-09-23 0intro need = 1;
1020 6f4d00ee 2013-09-23 0intro if(s->lastArch == 0){
1021 6f4d00ee 2013-09-23 0intro s->lastArch = 1;
1022 6f4d00ee 2013-09-23 0intro if(fsNeedArch(s->fs, s->archMinute))
1023 6f4d00ee 2013-09-23 0intro need = 1;
1025 6f4d00ee 2013-09-23 0intro if(need){
1026 6f4d00ee 2013-09-23 0intro fsSnapshot(s->fs, nil, nil, 1);
1027 6f4d00ee 2013-09-23 0intro s->lastArch = now;
1032 6f4d00ee 2013-09-23 0intro * Snapshot cleanup happens every snaplife or every day.
1034 6f4d00ee 2013-09-23 0intro snaplife = s->snapLife;
1035 6f4d00ee 2013-09-23 0intro if(snaplife == ~0)
1036 6f4d00ee 2013-09-23 0intro snaplife = 24*60;
1037 6f4d00ee 2013-09-23 0intro if(s->lastCleanup+snaplife < now){
1038 6f4d00ee 2013-09-23 0intro fsSnapshotCleanup(s->fs, s->snapLife);
1039 6f4d00ee 2013-09-23 0intro s->lastCleanup = now;
1041 4b576658 2013-09-23 0intro qunlock(&s->lk);
1044 6f4d00ee 2013-09-23 0intro static Snap*
1045 6f4d00ee 2013-09-23 0intro snapInit(Fs *fs)
1047 6f4d00ee 2013-09-23 0intro Snap *s;
1049 4b576658 2013-09-23 0intro s = vtmallocz(sizeof(Snap));
1050 6f4d00ee 2013-09-23 0intro s->fs = fs;
1051 6f4d00ee 2013-09-23 0intro s->tick = periodicAlloc(snapEvent, s, 10*1000);
1052 6f4d00ee 2013-09-23 0intro s->snapMinutes = -1;
1053 6f4d00ee 2013-09-23 0intro s->archMinute = -1;
1054 6f4d00ee 2013-09-23 0intro s->snapLife = -1;
1055 6f4d00ee 2013-09-23 0intro s->ignore = 5*2; /* wait five minutes for clock to stabilize */
1056 6f4d00ee 2013-09-23 0intro return s;
1060 6f4d00ee 2013-09-23 0intro snapGetTimes(Snap *s, u32int *arch, u32int *snap, u32int *snaplen)
1062 6f4d00ee 2013-09-23 0intro if(s == nil){
1063 6f4d00ee 2013-09-23 0intro *snap = -1;
1064 6f4d00ee 2013-09-23 0intro *arch = -1;
1065 6f4d00ee 2013-09-23 0intro *snaplen = -1;
1069 4b576658 2013-09-23 0intro qlock(&s->lk);
1070 6f4d00ee 2013-09-23 0intro *snap = s->snapMinutes;
1071 6f4d00ee 2013-09-23 0intro *arch = s->archMinute;
1072 6f4d00ee 2013-09-23 0intro *snaplen = s->snapLife;
1073 4b576658 2013-09-23 0intro qunlock(&s->lk);
1077 6f4d00ee 2013-09-23 0intro snapSetTimes(Snap *s, u32int arch, u32int snap, u32int snaplen)
1079 6f4d00ee 2013-09-23 0intro if(s == nil)
1082 4b576658 2013-09-23 0intro qlock(&s->lk);
1083 6f4d00ee 2013-09-23 0intro s->snapMinutes = snap;
1084 6f4d00ee 2013-09-23 0intro s->archMinute = arch;
1085 6f4d00ee 2013-09-23 0intro s->snapLife = snaplen;
1086 4b576658 2013-09-23 0intro qunlock(&s->lk);
1089 6f4d00ee 2013-09-23 0intro static void
1090 6f4d00ee 2013-09-23 0intro snapClose(Snap *s)
1092 6f4d00ee 2013-09-23 0intro if(s == nil)
1095 6f4d00ee 2013-09-23 0intro periodicKill(s->tick);
1096 4b576658 2013-09-23 0intro vtfree(s);