1 #include "logfsos.h"
2 #include "logfs.h"
3 #include "local.h"
4
5 void
logfsfreeanddirtydatablockcheck(LogfsServer * server,long seq)6 logfsfreeanddirtydatablockcheck(LogfsServer *server, long seq)
7 {
8 DataBlock *db;
9 Pageset mask, allpages;
10
11 if(seq >= server->ndatablocks)
12 return;
13 db = server->datablock + seq;
14 if(db->block < 0)
15 return;
16
17 mask = db->dirty & db->free;
18 if(mask) {
19 allpages = logfsdatapagemask(1 << server->ll->l2pagesperblock, 0);
20 if((mask & allpages) == allpages) {
21 //print("logfsfreedatapages: returning block to the wild\n");
22 logfsbootfettleblock(server->lb, db->block, LogfsTnone, ~0, nil);
23 db->block = -1;
24 if(seq == server->ndatablocks - 1)
25 server->ndatablocks--;
26 }
27 }
28 }
29
30 void
logfsfreedatapages(LogfsServer * server,long seq,Pageset mask)31 logfsfreedatapages(LogfsServer *server, long seq, Pageset mask)
32 {
33 DataBlock *db;
34 if(seq >= server->ndatablocks)
35 return;
36 db = server->datablock + seq;
37 if(db->block < 0)
38 return;
39 //print("logfsfreedatapages: index %ld mask 0x%.8ux\n", seq, mask);
40 db->dirty |= mask;
41 db->free |= mask;
42 logfsfreeanddirtydatablockcheck(server, seq);
43 }
44
45 int
logfsunconditionallymarkfreeanddirty(void * magic,Extent * e,int hole)46 logfsunconditionallymarkfreeanddirty(void *magic, Extent *e, int hole)
47 {
48 if(!hole && (e->flashaddr & LogAddr) == 0) {
49 LogfsServer *server = magic;
50 LogfsLowLevel *ll = server->ll;
51 DataBlock *db;
52 long blockindex;
53 int page, offset, npages;
54 Pageset mask;
55
56 logfsflashaddr2spo(server, e->flashaddr, &blockindex, &page, &offset);
57 if(blockindex < server->ndatablocks && (db = server->datablock + blockindex)->block >= 0) {
58 npages = ((offset + e->max - e->min) + (1 << ll->l2pagesize) - 1) >> ll->l2pagesize;
59 mask = logfsdatapagemask(npages, page);
60 if((db->dirty & mask) != mask)
61 print("markfreeandirty: not all pages dirty\n");
62 //print("markfreeanddirty: datablock %ld mask 0x%.8ux\n", blockindex, mask);
63 logfsfreedatapages(server, blockindex, mask);
64 }
65 else
66 print("markfreeanddirty: data block index %ld invalid\n", blockindex);
67 }
68 return 1;
69 }
70
71 char *
logfsserverremove(LogfsServer * server,u32int fid)72 logfsserverremove(LogfsServer *server, u32int fid)
73 {
74 Fid *f;
75 char *errmsg;
76 Entry *parent;
77 Entry *e, **ep;
78 ulong now;
79 char *uid;
80 LogMessage s;
81
82 if(server->trace > 1)
83 print("logfsserverremove(%ud)\n", fid);
84 f = logfsfidmapfindentry(server->fidmap, fid);
85 if(f == nil) {
86 errmsg = logfsebadfid;
87 goto clunk;
88 }
89 if((f->openmode & 3) == OWRITE) {
90 errmsg = logfseaccess;
91 goto clunk;
92 }
93 parent = f->entry->parent;
94 if(parent == f->entry) {
95 errmsg = Eperm;
96 goto clunk;
97 }
98 if((parent->qid.type & QTDIR) == 0) {
99 errmsg = logfseinternal;
100 goto clunk;
101 }
102 if(!logfsuserpermcheck(server, parent, f, DMWRITE)) {
103 errmsg = Eperm;
104 goto clunk;
105 }
106 if((f->entry->qid.type & QTDIR) != 0 && f->entry->u.dir.list) {
107 errmsg = logfsenotempty;
108 goto clunk;
109 }
110 if(f->entry->deadandgone) {
111 errmsg = Eio;
112 goto clunk;
113 }
114 for(ep = &parent->u.dir.list; e = *ep; ep = &e->next)
115 if(e == f->entry)
116 break;
117 if(e == nil) {
118 errmsg = logfseinternal;
119 goto clunk;
120 }
121 now = logfsnow();
122 uid = logfsisfindidfromname(server->is, f->uname);
123 /* log it */
124 s.type = LogfsLogTremove;
125 s.path = e->qid.path;
126 s.u.remove.mtime = e->mtime;
127 s.u.remove.muid = e->muid;
128 errmsg = logfslog(server, 1, &s);
129 if(errmsg)
130 goto clunk;
131 parent->mtime = now;
132 parent->muid = uid;
133 logfspathmapdeleteentry(server->pathmap, e->qid.path);
134 *ep = e->next; /* so open can't find it */
135 e->deadandgone = 1; /* so that other fids don't work any more */
136 /*
137 * lose the storage now, as deadandgone will prevent access
138 */
139 if((e->qid.type & QTDIR) == 0) {
140 logfsextentlistwalk(e->u.file.extent, logfsunconditionallymarkfreeanddirty, server);
141 logfsextentlistfree(&e->u.file.extent);
142 }
143 e->inuse--; /* so that the entryclunk removes the storage */
144 errmsg = nil;
145 clunk:
146 logfsfidmapclunk(server->fidmap, fid);
147 return errmsg;
148 }
149