xref: /inferno-os/liblogfs/remove.c (revision 28942ead413418b56c5be78e8c4c400881fba72e)
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