xref: /inferno-os/liblogfs/remove.c (revision 46439007cf417cbd9ac8049bb4122c890097a0fa)
1 #include "lib9.h"
2 #include "logfs.h"
3 #include "local.h"
4 
5 void
6 logfsfreeanddirtydatablockcheck(LogfsServer *server, long seq)
7 {
8 	DataBlock *db;
9 	u32int mask;
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 		u32int 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
31 logfsfreedatapages(LogfsServer *server, long seq, u32int 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
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;
54 		logfsflashaddr2spo(server, e->flashaddr, &blockindex, &page, &offset);
55 		if(blockindex < server->ndatablocks && (db = server->datablock + blockindex)->block >= 0) {
56 			int npages = ((offset + e->max - e->min) + (1 << ll->l2pagesize) - 1) >> ll->l2pagesize;
57 			u32int mask = logfsdatapagemask(npages, page);
58 			if((db->dirty & mask) != mask)
59 				print("markfreeandirty: not all pages dirty\n");
60 //print("markfreeanddirty: datablock %ld mask 0x%.8ux\n", blockindex, mask);
61 			logfsfreedatapages(server, blockindex, mask);
62 		}
63 		else
64 			print("markfreeanddirty: data block index %ld invalid\n", blockindex);
65 	}
66 	return 1;
67 }
68 
69 char *
70 logfsserverremove(LogfsServer *server, u32int fid)
71 {
72 	Fid *f;
73 	char *errmsg;
74 	Entry *parent;
75 	Entry *e, **ep;
76 	ulong now;
77 	char *uid;
78 	LogMessage s;
79 
80 	if(server->trace > 1)
81 		print("logfsserverremove(%ud)\n", fid);
82 	f = logfsfidmapfindentry(server->fidmap, fid);
83 	if(f == nil) {
84 		errmsg = logfsebadfid;
85 		goto clunk;
86 	}
87 	if((f->openmode & 3) == OWRITE) {
88 		errmsg = logfseaccess;
89 		goto clunk;
90 	}
91 	parent = f->entry->parent;
92 	if(parent == f->entry) {
93 		errmsg = Eperm;
94 		goto clunk;
95 	}
96 	if((parent->qid.type & QTDIR) == 0) {
97 		errmsg = logfseinternal;
98 		goto clunk;
99 	}
100 	if(!logfsuserpermcheck(server, parent, f, DMWRITE)) {
101 		errmsg = Eperm;
102 		goto clunk;
103 	}
104 	if((f->entry->qid.type & QTDIR) != 0 && f->entry->u.dir.list) {
105 		errmsg = logfsenotempty;
106 		goto clunk;
107 	}
108 	if(f->entry->deadandgone) {
109 		errmsg = Eio;
110 		goto clunk;
111 	}
112 	for(ep = &parent->u.dir.list; e = *ep; ep = &e->next)
113 		if(e == f->entry)
114 			break;
115 	if(e == nil) {
116 		errmsg = logfseinternal;
117 		goto clunk;
118 	}
119 	now = logfsnow();
120 	uid = logfsisfindidfromname(server->is, f->uname);
121 	/* log it */
122 	s.type = LogfsLogTremove;
123 	s.path = e->qid.path;
124 	s.u.remove.mtime = e->mtime;
125 	s.u.remove.muid = e->muid;
126 	errmsg = logfslog(server, 1, &s);
127 	if(errmsg)
128 		goto clunk;
129 	parent->mtime = now;
130 	parent->muid = uid;
131 	logfspathmapdeleteentry(server->pathmap, e->qid.path);
132 	*ep = e->next;				/* so open can't find it */
133 	e->deadandgone = 1;		/* so that other fids don't work any more */
134 	/*
135 	 * lose the storage now, as deadandgone will prevent access
136 	 */
137 	if((e->qid.type & QTDIR) == 0) {
138 		logfsextentlistwalk(e->u.file.extent, logfsunconditionallymarkfreeanddirty, server);
139 		logfsextentlistfree(&e->u.file.extent);
140 	}
141 	e->inuse--;				/* so that the entryclunk removes the storage */
142 	errmsg = nil;
143 clunk:
144 	logfsfidmapclunk(server->fidmap, fid);
145 	return errmsg;
146 }
147 
148