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