xref: /inferno-os/liblogfs/remove.c (revision 5d0c4cf3fc288434c41cba52dd998ab1d7375a7b)
1  #include "logfsos.h"
2  #include "logfs.h"
3  #include "local.h"
4  
5  void
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
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
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 *
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