1 /*
2  * Copyright (C) 2016 Jakub Kruszona-Zawadzki, Core Technology Sp. z o.o.
3  *
4  * This file is part of MooseFS.
5  *
6  * MooseFS is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation, version 2 (only).
9  *
10  * MooseFS is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with MooseFS; if not, write to the Free Software
17  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02111-1301, USA
18  * or visit http://www.gnu.org/licenses/gpl-2.0.html
19  */
20 
21 #ifdef HAVE_CONFIG_H
22 #include "config.h"
23 #endif
24 
25 #include <stdlib.h>
26 #include <string.h>
27 #include <inttypes.h>
28 
29 #include "MFSCommunication.h"
30 #include "openfiles.h"
31 #include "metadata.h"
32 #include "sessions.h"
33 #include "changelog.h"
34 #include "main.h"
35 #include "datapack.h"
36 #include "bio.h"
37 #include "massert.h"
38 
39 #define OF_INODE_HASHSIZE 65536
40 #define OF_SESSION_HASHSIZE 4096
41 
42 #define OF_INODE_HASH(inode) ((inode)%(OF_INODE_HASHSIZE))
43 #define OF_SESSION_HASH(sessionid) ((sessionid)%(OF_SESSION_HASHSIZE))
44 
45 typedef struct _ofrelation {
46 	uint32_t sessionid;
47 	uint32_t inode;
48 	struct _ofrelation *snext,**sprev;
49 	struct _ofrelation *inext,**iprev;
50 } ofrelation;
51 
52 static ofrelation *sessionhash[OF_SESSION_HASHSIZE];
53 static ofrelation *inodehash[OF_INODE_HASHSIZE];
54 
55 
of_newnode(uint32_t sessionid,uint32_t inode)56 static inline void of_newnode(uint32_t sessionid,uint32_t inode) {
57 	ofrelation *ofr;
58 	uint32_t shashpos = OF_SESSION_HASH(sessionid);
59 	uint32_t ihashpos = OF_INODE_HASH(inode);
60 
61 //	syslog(LOG_NOTICE,"new node: sessionid: %"PRIu32", inode: %"PRIu32" , shashpos: %"PRIu32" , ihashpos: %"PRIu32,sessionid,inode,shashpos,ihashpos);
62 
63 	ofr = (ofrelation*)malloc(sizeof(ofrelation));
64 	ofr->sessionid = sessionid;
65 	ofr->inode = inode;
66 
67 	ofr->inext = inodehash[ihashpos];
68 	ofr->iprev = inodehash+ihashpos;
69 	if (ofr->inext) {
70 		ofr->inext->iprev = &(ofr->inext);
71 	}
72 	inodehash[ihashpos] = ofr;
73 
74 	ofr->snext = sessionhash[shashpos];
75 	ofr->sprev = sessionhash+shashpos;
76 	if (ofr->snext) {
77 		ofr->snext->sprev = &(ofr->snext);
78 	}
79 	sessionhash[shashpos] = ofr;
80 }
81 
of_delnode(ofrelation * ofr)82 static inline void of_delnode(ofrelation *ofr) {
83 //	syslog(LOG_NOTICE,"del node: sessionid: %"PRIu32", inode: %"PRIu32,ofr->sessionid,ofr->inode);
84 	*(ofr->iprev) = ofr->inext;
85 	if (ofr->inext) {
86 		ofr->inext->iprev = ofr->iprev;
87 	}
88 	*(ofr->sprev) = ofr->snext;
89 	if (ofr->snext) {
90 		ofr->snext->sprev = ofr->sprev;
91 	}
92 	free(ofr);
93 }
94 
of_checknode(uint32_t sessionid,uint32_t inode)95 static inline uint8_t of_checknode(uint32_t sessionid,uint32_t inode) {
96 	ofrelation *ofr;
97 	uint32_t ihashpos = OF_INODE_HASH(inode);
98 
99 //	syslog(LOG_NOTICE,"check node: sessionid: %"PRIu32", inode: %"PRIu32" , ihashpos: %"PRIu32,sessionid,inode,ihashpos);
100 	for (ofr = inodehash[ihashpos] ; ofr ; ofr = ofr->inext) {
101 //		syslog(LOG_NOTICE,"check node: pointer: %p (sessionid: %"PRIu32", inode: %"PRIu32")",ofr,ofr->sessionid,ofr->inode);
102 		if (ofr->sessionid==sessionid && ofr->inode==inode) {
103 //			syslog(LOG_NOTICE,"check node: found");
104 			return 1;
105 		}
106 	}
107 //	syslog(LOG_NOTICE,"check node: not found");
108 	return 0;
109 }
110 
111 
of_bisearch(uint32_t search,const uint32_t * array,uint32_t n)112 static inline int32_t of_bisearch(uint32_t search,const uint32_t *array,uint32_t n) {
113 	int32_t first,last,middle;
114 
115 	first = 0;
116 	last = n - 1;
117 	middle = (first + last) / 2;
118 
119 	while (first<=last) {
120 		if (array[middle] < search) {
121 			first = middle + 1;
122 		} else if (array[middle] > search) {
123 			last = middle - 1;
124 		} else {
125 			return middle;
126 		}
127 		middle = (first + last) / 2;
128 	}
129 	return -1;
130 }
131 
of_inodecmp(const void * a,const void * b)132 int of_inodecmp(const void *a,const void *b) {
133 	uint32_t aa = *((const uint32_t*)a);
134 	uint32_t bb = *((const uint32_t*)b);
135 	if (aa<bb) {
136 		return -1;
137 	} else if (aa>bb) {
138 		return 1;
139 	} else {
140 		return 0;
141 	}
142 }
143 
144 
of_sync(uint32_t sessionid,uint32_t * inodes,uint32_t inodecnt)145 void of_sync(uint32_t sessionid,uint32_t *inodes,uint32_t inodecnt) {
146 	static uint32_t *bitmask=NULL;
147 	static uint32_t bitmasksize=0;
148 	ofrelation *ofr,*nofr;
149 	int32_t ipos;
150 	uint32_t i;
151 	uint32_t shashpos = OF_SESSION_HASH(sessionid);
152 
153 	if (inodecnt > bitmasksize*32) {
154 		if (bitmask) {
155 			free(bitmask);
156 		}
157 		bitmasksize = ((inodecnt+31)/32)+10;
158 		bitmask = malloc(sizeof(uint32_t)*bitmasksize);
159 		passert(bitmask);
160 	}
161 
162 	memset(bitmask,0,sizeof(uint32_t)*bitmasksize);
163 
164 	qsort(inodes,inodecnt,sizeof(uint32_t),of_inodecmp);
165 
166 //	for (i=0 ; i<inodecnt ; i++) {
167 //		syslog(LOG_NOTICE,"sync: inodes[%"PRIu32"]=%"PRIu32,i,inodes[i]);
168 //	}
169 
170 	for (ofr = sessionhash[shashpos] ; ofr ; ofr = nofr) {
171 		nofr = ofr->snext;
172 		if (ofr->sessionid==sessionid) {
173 			ipos = of_bisearch(ofr->inode,inodes,inodecnt);
174 //			syslog(LOG_NOTICE,"sync: search for %"PRIu32" -> pos: %"PRId32,ofr->inode,ipos);
175 			if (ipos<0) { // close
176 				changelog("%"PRIu32"|RELEASE(%"PRIu32",%"PRIu32")",main_time(),ofr->sessionid,ofr->inode);
177 				of_delnode(ofr);
178 			} else {
179 				bitmask[ipos>>5] |= (1U<<(ipos&0x1F));
180 			}
181 		}
182 	}
183 
184 //	for (i=0 ; i<bitmasksize ; i++) {
185 //		syslog(LOG_NOTICE,"sync: bitmask[%"PRIu32"]=%"PRIX32,i,bitmask[i]);
186 //	}
187 
188 	for (i=0 ; i<inodecnt ; i++) {
189 		if ((bitmask[i>>5] & (1U<<(i&0x1F)))==0) {
190 			changelog("%"PRIu32"|ACQUIRE(%"PRIu32",%"PRIu32")",main_time(),sessionid,inodes[i]);
191 			of_newnode(sessionid,inodes[i]);
192 		}
193 	}
194 }
195 
196 
of_openfile(uint32_t sessionid,uint32_t inode)197 void of_openfile(uint32_t sessionid,uint32_t inode) {
198 	if (of_checknode(sessionid,inode)==0) {
199 		changelog("%"PRIu32"|ACQUIRE(%"PRIu32",%"PRIu32")",main_time(),sessionid,inode);
200 		of_newnode(sessionid,inode);
201 	}
202 }
203 
of_sessionremoved(uint32_t sessionid)204 void of_sessionremoved(uint32_t sessionid) {
205 	ofrelation *ofr,*nofr;
206 	uint32_t shashpos = OF_SESSION_HASH(sessionid);
207 
208 	for (ofr = sessionhash[shashpos] ; ofr ; ofr = nofr) {
209 		nofr = ofr->snext;
210 		if (ofr->sessionid==sessionid) {
211 			of_delnode(ofr);
212 		}
213 	}
214 }
215 
of_isfileopened(uint32_t inode)216 uint8_t of_isfileopened(uint32_t inode) {
217 	ofrelation *ofr;
218 	uint32_t ihashpos = OF_INODE_HASH(inode);
219 
220 	for (ofr = inodehash[ihashpos] ; ofr ; ofr = ofr->inext) {
221 		if (ofr->inode==inode) {
222 			return 1;
223 		}
224 	}
225 	return 0;
226 }
227 
of_noofopenedfiles(uint32_t sessionid)228 uint32_t of_noofopenedfiles(uint32_t sessionid) {
229 	ofrelation *ofr;
230 	uint32_t shashpos = OF_SESSION_HASH(sessionid);
231 	uint32_t cnt = 0;
232 
233 	for (ofr = sessionhash[shashpos] ; ofr ; ofr = ofr->snext) {
234 		if (ofr->sessionid==sessionid) {
235 			cnt++;
236 		}
237 	}
238 	return cnt;
239 }
240 
of_mr_acquire(uint32_t sessionid,uint32_t inode)241 int of_mr_acquire(uint32_t sessionid,uint32_t inode) {
242 	if (of_checknode(sessionid,inode)) {
243 		return ERROR_MISMATCH;
244 	}
245 	of_newnode(sessionid,inode);
246 	meta_version_inc();
247 	return STATUS_OK;
248 }
249 
of_mr_release(uint32_t sessionid,uint32_t inode)250 int of_mr_release(uint32_t sessionid,uint32_t inode) {
251 	ofrelation *ofr,*nofr;
252 	uint32_t ihashpos = OF_INODE_HASH(inode);
253 
254 	for (ofr = inodehash[ihashpos] ; ofr ; ofr = nofr) {
255 		nofr = ofr->inext;
256 		if (ofr->sessionid==sessionid && ofr->inode==inode) {
257 			of_delnode(ofr);
258 			meta_version_inc();
259 			return STATUS_OK;
260 		}
261 	}
262 	return ERROR_MISMATCH;
263 }
264 
265 #define OF_STORE_BLOCK_CNT 256
266 #define OF_REC_SIZE 8
267 
of_store(bio * fd)268 uint8_t of_store(bio *fd) {
269 	uint8_t storebuff[OF_REC_SIZE*OF_STORE_BLOCK_CNT];
270 	uint8_t *ptr;
271 	ofrelation *ofr;
272 	uint32_t i,j;
273 	uint32_t sessionid,inode;
274 
275 	if (fd==NULL) {
276 		return 0x10;
277 	}
278 	j=0;
279 	ptr = storebuff;
280 	for (i=0 ; i<OF_SESSION_HASHSIZE ; i++) {
281 		for (ofr = sessionhash[i] ; ofr ; ofr=ofr->snext) {
282 			sessionid = ofr->sessionid;
283 			inode = ofr->inode;
284 			put32bit(&ptr,sessionid);
285 			put32bit(&ptr,inode);
286 			j++;
287 			if (j==OF_STORE_BLOCK_CNT) {
288 				if (bio_write(fd,storebuff,OF_REC_SIZE*OF_STORE_BLOCK_CNT)!=(OF_REC_SIZE*OF_STORE_BLOCK_CNT)) {
289 					return 0xFF;
290 				}
291 				j=0;
292 				ptr = storebuff;
293 			}
294 		}
295 	}
296 	memset(ptr,0,OF_REC_SIZE);
297 	j++;
298 	if (bio_write(fd,storebuff,OF_REC_SIZE*j)!=(OF_REC_SIZE*j)) {
299 		return 0xFF;
300 	}
301 	return 0;
302 }
303 
of_load(bio * fd,uint8_t mver)304 int of_load(bio *fd,uint8_t mver) {
305 	uint8_t loadbuff[OF_REC_SIZE];
306 	const uint8_t *ptr;
307 	int32_t r;
308 	uint32_t sessionid,inode;
309 
310 	(void)mver;
311 
312 	for (;;) {
313 		r = bio_read(fd,loadbuff,OF_REC_SIZE);
314 		if (r!=OF_REC_SIZE) {
315 			return -1;
316 		}
317 		ptr = loadbuff;
318 		sessionid = get32bit(&ptr);
319 		inode = get32bit(&ptr);
320 		if (sessionid>0 && inode>0) {
321 			if (sessions_find_session(sessionid)!=NULL) {
322 				of_newnode(sessionid,inode);
323 			}
324 		} else if (sessionid==0 && inode==0) {
325 			return 0;
326 		} else {
327 			return -1;
328 		}
329 	}
330 	return 0;	// unreachable
331 }
332 
of_cleanup(void)333 void of_cleanup(void) {
334 	ofrelation *ofr,*nofr;
335 	uint32_t i;
336 
337 	for (i=0 ; i<OF_SESSION_HASHSIZE ; i++) {
338 		for (ofr = sessionhash[i] ; ofr ; ofr=nofr) {
339 			nofr = ofr->snext;
340 			free(ofr);
341 		}
342 		sessionhash[i] = NULL;
343 	}
344 	for (i=0 ; i<OF_INODE_HASHSIZE ; i++) {
345 		inodehash[i] = NULL;
346 	}
347 }
348 
of_init(void)349 int of_init(void) {
350 	uint32_t i;
351 
352 	for (i=0 ; i<OF_SESSION_HASHSIZE ; i++) {
353 		sessionhash[i] = NULL;
354 	}
355 	for (i=0 ; i<OF_INODE_HASHSIZE ; i++) {
356 		inodehash[i] = NULL;
357 	}
358 	return 0;
359 }
360