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 <fuse_lowlevel.h>
26 #include <stdlib.h>
27 #include <string.h>
28 #include <pthread.h>
29
30 #include "massert.h"
31 #include "datapack.h"
32
33 typedef struct _dircache {
34 struct fuse_ctx ctx;
35 uint32_t parent;
36 const uint8_t *dbuff;
37 uint32_t dsize;
38 uint32_t hashsize;
39 const uint8_t **namehashtab;
40 const uint8_t **inodehashtab;
41 struct _dircache *next,**prev;
42 } dircache;
43
44 static dircache *head;
45 static pthread_mutex_t glock = PTHREAD_MUTEX_INITIALIZER;
46
dcache_hash(const uint8_t * name,uint8_t nleng)47 static inline uint32_t dcache_hash(const uint8_t *name,uint8_t nleng) {
48 uint32_t hash=5381;
49 while (nleng>0) {
50 hash = ((hash<<5)+hash)^(*name);
51 name++;
52 nleng--;
53 }
54 return hash;
55 }
56
dcache_elemcount(const uint8_t * dbuff,uint32_t dsize)57 uint32_t dcache_elemcount(const uint8_t *dbuff,uint32_t dsize) {
58 const uint8_t *ptr,*eptr;
59 uint8_t enleng;
60 uint32_t ret;
61 ptr = dbuff;
62 eptr = dbuff+dsize;
63 ret=0;
64 while (ptr<eptr) {
65 enleng = *ptr;
66 if (ptr+enleng+40<=eptr) {
67 ret++;
68 }
69 ptr+=enleng+40;
70 }
71 return ret;
72 }
73
dcache_calchashsize(dircache * d)74 static inline void dcache_calchashsize(dircache *d) {
75 uint32_t cnt = dcache_elemcount(d->dbuff,d->dsize);
76 d->hashsize = 1;
77 cnt = (cnt*3)/2;
78 while (cnt) {
79 d->hashsize<<=1;
80 cnt>>=1;
81 }
82 }
83
dcache_makenamehash(dircache * d)84 void dcache_makenamehash(dircache *d) {
85 const uint8_t *ptr,*eptr;
86 uint8_t enleng;
87 uint32_t hash,disp;
88 uint32_t hashmask;
89
90 if (d->hashsize==0) {
91 dcache_calchashsize(d);
92 }
93 hashmask = d->hashsize-1;
94 d->namehashtab = malloc(sizeof(uint8_t*)*d->hashsize);
95 memset(d->namehashtab,0,sizeof(uint8_t*)*d->hashsize);
96
97 ptr = d->dbuff;
98 eptr = d->dbuff+d->dsize;
99 while (ptr<eptr) {
100 enleng = *ptr;
101 if (ptr+enleng+40<=eptr) {
102 hash = dcache_hash(ptr+1,enleng);
103 disp = ((hash*0x53B23891)&hashmask)|1;
104 while (d->namehashtab[hash&hashmask]) {
105 hash+=disp;
106 }
107 d->namehashtab[hash&hashmask]=ptr;
108 }
109 ptr+=enleng+40;
110 }
111 }
112
dcache_makeinodehash(dircache * d)113 void dcache_makeinodehash(dircache *d) {
114 const uint8_t *iptr,*ptr,*eptr;
115 uint8_t enleng;
116 uint32_t hash,disp;
117 uint32_t hashmask;
118
119 if (d->hashsize==0) {
120 dcache_calchashsize(d);
121 }
122 hashmask = d->hashsize-1;
123 d->inodehashtab = malloc(sizeof(uint8_t*)*d->hashsize);
124 memset(d->inodehashtab,0,sizeof(uint8_t*)*d->hashsize);
125
126 ptr = d->dbuff;
127 eptr = d->dbuff+d->dsize;
128 while (ptr<eptr) {
129 enleng = *ptr;
130 if (ptr+enleng+40<=eptr) {
131 iptr = ptr+1+enleng;
132 hash = get32bit(&iptr);
133 disp = ((hash*0x53B23891)&hashmask)|1;
134 hash *= 0xB28E457D;
135 while (d->inodehashtab[hash&hashmask]) {
136 hash+=disp;
137 }
138 d->inodehashtab[hash&hashmask]=ptr+1+enleng;
139 }
140 ptr+=enleng+40;
141 }
142 }
143
dcache_new(const struct fuse_ctx * ctx,uint32_t parent,const uint8_t * dbuff,uint32_t dsize)144 void* dcache_new(const struct fuse_ctx *ctx,uint32_t parent,const uint8_t *dbuff,uint32_t dsize) {
145 dircache *d;
146 d = malloc(sizeof(dircache));
147 d->ctx.pid = ctx->pid;
148 d->ctx.uid = ctx->uid;
149 d->ctx.gid = ctx->gid;
150 d->parent = parent;
151 d->dbuff = dbuff;
152 d->dsize = dsize;
153 d->hashsize = 0;
154 d->namehashtab = NULL;
155 d->inodehashtab = NULL;
156 zassert(pthread_mutex_lock(&glock));
157 if (head) {
158 head->prev = &(d->next);
159 }
160 d->next = head;
161 d->prev = &head;
162 head = d;
163 zassert(pthread_mutex_unlock(&glock));
164 return d;
165 }
166
dcache_release(void * r)167 void dcache_release(void *r) {
168 dircache *d = (dircache*)r;
169 zassert(pthread_mutex_lock(&glock));
170 if (d->next) {
171 d->next->prev = d->prev;
172 }
173 *(d->prev) = d->next;
174 zassert(pthread_mutex_unlock(&glock));
175 if (d->namehashtab) {
176 free(d->namehashtab);
177 }
178 if (d->inodehashtab) {
179 free(d->inodehashtab);
180 }
181 free(d);
182 }
183
184 /*
185 static inline uint8_t dcache_namesearch(const uint8_t *dbuff,uint32_t dsize,uint8_t nleng,const uint8_t *name,uint32_t *inode,uint8_t attr[35]) {
186 const uint8_t *ptr,*eptr;
187 uint8_t enleng;
188 ptr = dbuff;
189 eptr = dbuff+dsize;
190 while (ptr<eptr) {
191 enleng = *ptr;
192 if (ptr+enleng+40<=eptr && enleng==nleng && memcmp(ptr+1,name,enleng)==0) {
193 ptr+=1+enleng;
194 *inode = get32bit(&ptr);
195 memcpy(attr,ptr,35);
196 return 1;
197 }
198 ptr+=enleng+40;
199 }
200 return 0;
201 }
202
203 static inline uint8_t dcache_inodesearch(const uint8_t *dbuff,uint32_t dsize,uint32_t inode,uint8_t attr[35]) {
204 const uint8_t *ptr,*eptr;
205 uint8_t enleng;
206 ptr = dbuff;
207 eptr = dbuff+dsize;
208 while (ptr<eptr) {
209 enleng = *ptr;
210 if (ptr+enleng+40<=eptr) {
211 ptr+=1+enleng;
212 if (inode==get32bit(&ptr)) {
213 memcpy(attr,ptr,35);
214 return 1;
215 } else {
216 ptr+=35;
217 }
218 } else {
219 return 0;
220 }
221 }
222 return 0;
223 }
224 */
225
dcache_namehash_invalidate(dircache * d,uint8_t nleng,const uint8_t * name)226 static inline void dcache_namehash_invalidate(dircache *d,uint8_t nleng,const uint8_t *name) {
227 uint32_t hash,disp,hashmask;
228 const uint8_t *ptr;
229
230 if (d->namehashtab==NULL) {
231 dcache_makenamehash(d);
232 }
233 hashmask = d->hashsize-1;
234 hash = dcache_hash(name,nleng);
235 disp = ((hash*0x53B23891)&hashmask)|1;
236 while ((ptr=d->namehashtab[hash&hashmask])) {
237 if (*ptr==nleng && memcmp(ptr+1,name,nleng)==0) {
238 ptr+=1+nleng;
239 memset((uint8_t*)ptr,0,sizeof(uint32_t)+35);
240 return;
241 }
242 hash+=disp;
243 }
244 }
245
dcache_namehash_get(dircache * d,uint8_t nleng,const uint8_t * name,uint32_t * inode,uint8_t attr[35])246 static inline uint8_t dcache_namehash_get(dircache *d,uint8_t nleng,const uint8_t *name,uint32_t *inode,uint8_t attr[35]) {
247 uint32_t hash,disp,hashmask;
248 const uint8_t *ptr;
249
250 if (d->namehashtab==NULL) {
251 dcache_makenamehash(d);
252 }
253 hashmask = d->hashsize-1;
254 hash = dcache_hash(name,nleng);
255 disp = ((hash*0x53B23891)&hashmask)|1;
256 while ((ptr=d->namehashtab[hash&hashmask])) {
257 if (*ptr==nleng && memcmp(ptr+1,name,nleng)==0) {
258 ptr+=1+nleng;
259 *inode = get32bit(&ptr);
260 if (*ptr) { // are attributes valid ?
261 memcpy(attr,ptr,35);
262 return 1;
263 } else {
264 return 0;
265 }
266 }
267 hash+=disp;
268 }
269 return 0;
270 }
271
dcache_inodehash_get(dircache * d,uint32_t inode,uint8_t attr[35])272 static inline uint8_t dcache_inodehash_get(dircache *d,uint32_t inode,uint8_t attr[35]) {
273 uint32_t hash,disp,hashmask;
274 const uint8_t *ptr;
275
276 if (d->inodehashtab==NULL) {
277 dcache_makeinodehash(d);
278 }
279 hashmask = d->hashsize-1;
280 hash = inode*0xB28E457D;
281 disp = ((inode*0x53B23891)&hashmask)|1;
282 while ((ptr=d->inodehashtab[hash&hashmask])) {
283 if (inode==get32bit(&ptr)) {
284 if (*ptr) { // are attributes valid ?
285 memcpy(attr,ptr,35);
286 return 1;
287 } else {
288 return 0;
289 }
290 }
291 hash+=disp;
292 }
293 return 0;
294 }
295
dcache_inodehash_set(dircache * d,uint32_t inode,const uint8_t attr[35])296 static inline uint8_t dcache_inodehash_set(dircache *d,uint32_t inode,const uint8_t attr[35]) {
297 uint32_t hash,disp,hashmask;
298 const uint8_t *ptr;
299
300 if (d->inodehashtab==NULL) {
301 dcache_makeinodehash(d);
302 }
303 hashmask = d->hashsize-1;
304 hash = inode*0xB28E457D;
305 disp = ((inode*0x53B23891)&hashmask)|1;
306 while ((ptr=d->inodehashtab[hash&hashmask])) {
307 if (inode==get32bit(&ptr)) {
308 memcpy((uint8_t*)ptr,attr,35);
309 return 1;
310 }
311 hash+=disp;
312 }
313 return 0;
314 }
315
dcache_inodehash_invalidate_attr(dircache * d,uint32_t inode)316 static inline uint8_t dcache_inodehash_invalidate_attr(dircache *d,uint32_t inode) {
317 uint32_t hash,disp,hashmask;
318 const uint8_t *ptr;
319
320 if (d->inodehashtab==NULL) {
321 dcache_makeinodehash(d);
322 }
323 hashmask = d->hashsize-1;
324 hash = inode*0xB28E457D;
325 disp = ((inode*0x53B23891)&hashmask)|1;
326 while ((ptr=d->inodehashtab[hash&hashmask])) {
327 if (inode==get32bit(&ptr)) {
328 memset((uint8_t*)ptr,0,35);
329 return 1;
330 }
331 hash+=disp;
332 }
333 return 0;
334 }
335
dcache_lookup(const struct fuse_ctx * ctx,uint32_t parent,uint8_t nleng,const uint8_t * name,uint32_t * inode,uint8_t attr[35])336 uint8_t dcache_lookup(const struct fuse_ctx *ctx,uint32_t parent,uint8_t nleng,const uint8_t *name,uint32_t *inode,uint8_t attr[35]) {
337 dircache *d;
338 zassert(pthread_mutex_lock(&glock));
339 for (d=head ; d ; d=d->next) {
340 if (parent==d->parent && ctx->pid==d->ctx.pid && ctx->uid==d->ctx.uid && ctx->gid==d->ctx.gid) {
341 if (dcache_namehash_get(d,nleng,name,inode,attr)) {
342 zassert(pthread_mutex_unlock(&glock));
343 return 1;
344 }
345 }
346 }
347 zassert(pthread_mutex_unlock(&glock));
348 return 0;
349 }
350
dcache_getattr(const struct fuse_ctx * ctx,uint32_t inode,uint8_t attr[35])351 uint8_t dcache_getattr(const struct fuse_ctx *ctx,uint32_t inode,uint8_t attr[35]) {
352 dircache *d;
353 zassert(pthread_mutex_lock(&glock));
354 for (d=head ; d ; d=d->next) {
355 if (ctx->pid==d->ctx.pid && ctx->uid==d->ctx.uid && ctx->gid==d->ctx.gid) {
356 if (dcache_inodehash_get(d,inode,attr)) {
357 zassert(pthread_mutex_unlock(&glock));
358 return 1;
359 }
360 }
361 }
362 zassert(pthread_mutex_unlock(&glock));
363 return 0;
364 }
365
dcache_setattr(uint32_t inode,const uint8_t attr[35])366 void dcache_setattr(uint32_t inode,const uint8_t attr[35]) {
367 dircache *d;
368 zassert(pthread_mutex_lock(&glock));
369 for (d=head ; d ; d=d->next) {
370 dcache_inodehash_set(d,inode,attr);
371 }
372 zassert(pthread_mutex_unlock(&glock));
373 }
374
dcache_invalidate_attr(uint32_t inode)375 void dcache_invalidate_attr(uint32_t inode) {
376 dircache *d;
377 zassert(pthread_mutex_lock(&glock));
378 for (d=head ; d ; d=d->next) {
379 dcache_inodehash_invalidate_attr(d,inode);
380 }
381 zassert(pthread_mutex_unlock(&glock));
382 }
383
dcache_invalidate_name(const struct fuse_ctx * ctx,uint32_t parent,uint8_t nleng,const uint8_t * name)384 void dcache_invalidate_name(const struct fuse_ctx *ctx,uint32_t parent,uint8_t nleng,const uint8_t *name) {
385 dircache *d;
386 zassert(pthread_mutex_lock(&glock));
387 for (d=head ; d ; d=d->next) {
388 if (parent==d->parent && ctx->pid==d->ctx.pid && ctx->uid==d->ctx.uid && ctx->gid==d->ctx.gid) {
389 dcache_namehash_invalidate(d,nleng,name);
390 }
391 }
392 zassert(pthread_mutex_unlock(&glock));
393 }
394