1 /*
2  * Copyright (C) 2021 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 #define BUCKETS_MT_MMAP_ALLOC 1
26 
27 #include <stdlib.h>
28 #include <string.h>
29 #include <inttypes.h>
30 #include <pthread.h>
31 
32 #include "fusecommon.h"
33 
34 #include "MFSCommunication.h"
35 #include "chunksdatacache.h"
36 #include "massert.h"
37 #include "clocks.h"
38 #include "buckets_mt.h"
39 
40 #include "fdcache.h"
41 
42 #define FDCACHE_HASHSIZE 1024
43 #define FDCACHE_HASH(inode) ((inode)%FDCACHE_HASHSIZE)
44 #define FDCACHE_TIMEOUT 1.0
45 
46 typedef struct _fdcacheentry {
47 	double createtime;
48 	uid_t uid;
49 	gid_t gid;
50 	pid_t pid;
51 	uint32_t inode;
52 	uint8_t attr[35];
53 	uint16_t lflags;
54 	uint8_t csdataver;
55 	uint64_t chunkid;
56 	uint32_t version;
57 	uint32_t csdatasize;
58 	uint8_t csdata[10*14];
59 	struct _fdcacheentry *next;
60 } fdcacheentry;
61 
62 CREATE_BUCKET_MT_ALLOCATOR(fdcachee,fdcacheentry,500)
63 
64 static fdcacheentry *fdhashtab[FDCACHE_HASHSIZE];
65 static pthread_mutex_t hashlock[FDCACHE_HASHSIZE];
66 
fdcache_insert(const struct fuse_ctx * ctx,uint32_t inode,uint8_t attr[35],uint16_t lflags,uint8_t csdataver,uint64_t chunkid,uint32_t version,const uint8_t * csdata,uint32_t csdatasize)67 void fdcache_insert(const struct fuse_ctx *ctx,uint32_t inode,uint8_t attr[35],uint16_t lflags,uint8_t csdataver,uint64_t chunkid,uint32_t version,const uint8_t *csdata,uint32_t csdatasize) {
68 	uint32_t h;
69 	double now;
70 	fdcacheentry *f;
71 	fdcacheentry *fdce,**fdcep;
72 
73 	now = monotonic_seconds();
74 	h = FDCACHE_HASH(inode);
75 	zassert(pthread_mutex_lock(hashlock+h));
76 	fdcep = fdhashtab + h;
77 	f = NULL;
78 	while ((fdce = *fdcep)) {
79 		if (fdce->createtime + FDCACHE_TIMEOUT < now) {
80 			*fdcep = fdce->next;
81 			fdcachee_free(fdce);
82 		} else {
83 			if (fdce->inode==inode && fdce->uid==ctx->uid && fdce->gid==ctx->gid && fdce->pid==ctx->pid) {
84 				if (f==NULL) {
85 					f = fdce;
86 					fdcep = &(fdce->next);
87 				} else {
88 					*fdcep = fdce->next;
89 					fdcachee_free(fdce);
90 				}
91 			} else {
92 				fdcep = &(fdce->next);
93 			}
94 		}
95 	}
96 	if (f==NULL) {
97 		fdce = fdcachee_malloc();
98 		fdce->uid = ctx->uid;
99 		fdce->gid = ctx->gid;
100 		fdce->pid = ctx->pid;
101 		fdce->inode = inode;
102 		fdce->next = fdhashtab[h];
103 		fdhashtab[h] = fdce;
104 	} else {
105 		fdce = f;
106 	}
107 	fdce->createtime = now;
108 	memcpy(fdce->attr,attr,35);
109 	fdce->lflags = lflags;
110 	if ((lflags & LOOKUP_CHUNK_ZERO_DATA) && csdatasize<=(10*14)) {
111 		fdce->csdataver = csdataver;
112 		fdce->chunkid = chunkid;
113 		fdce->version = version;
114 		fdce->csdatasize = csdatasize;
115 		memcpy(fdce->csdata,csdata,csdatasize);
116 	} else {
117 		fdce->lflags &= ~LOOKUP_CHUNK_ZERO_DATA;
118 		fdce->csdataver = 0;
119 		fdce->chunkid = 0;
120 		fdce->version = 0;
121 		fdce->csdatasize = 0;
122 	}
123 	zassert(pthread_mutex_unlock(hashlock+h));
124 }
125 
fdcache_invalidate(uint32_t inode)126 void fdcache_invalidate(uint32_t inode) {
127 	uint32_t h;
128 	fdcacheentry *fdce,**fdcep;
129 
130 	h = FDCACHE_HASH(inode);
131 	zassert(pthread_mutex_lock(hashlock+h));
132 	fdcep = fdhashtab + h;
133 	while ((fdce = *fdcep)) {
134 		if (fdce->inode==inode) {
135 			*fdcep = fdce->next;
136 			fdcachee_free(fdce);
137 		} else {
138 			fdcep = &(fdce->next);
139 		}
140 	}
141 	zassert(pthread_mutex_unlock(hashlock+h));
142 }
143 
fdcache_find(const struct fuse_ctx * ctx,uint32_t inode,uint8_t attr[35],uint16_t * lflags)144 uint8_t fdcache_find(const struct fuse_ctx *ctx,uint32_t inode,uint8_t attr[35],uint16_t *lflags) {
145 	uint32_t h;
146 	double now;
147 	fdcacheentry *fdce;
148 	now = monotonic_seconds();
149 	h = FDCACHE_HASH(inode);
150 	zassert(pthread_mutex_lock(hashlock+h));
151 	for (fdce = fdhashtab[h] ; fdce!=NULL ; fdce = fdce->next) {
152 		if (fdce->inode==inode && fdce->uid==ctx->uid && fdce->gid==ctx->gid && fdce->pid==ctx->pid && fdce->createtime + FDCACHE_TIMEOUT >= now) {
153 			if (attr!=NULL) {
154 				memcpy(attr,fdce->attr,35);
155 			}
156 			if (lflags!=NULL) {
157 				*lflags = fdce->lflags;
158 			}
159 			zassert(pthread_mutex_unlock(hashlock+h));
160 			return 1;
161 		}
162 	}
163 	zassert(pthread_mutex_unlock(hashlock+h));
164 	return 0;
165 }
166 
fdcache_acquire(const struct fuse_ctx * ctx,uint32_t inode,uint8_t attr[35],uint16_t * lflags)167 void* fdcache_acquire(const struct fuse_ctx *ctx,uint32_t inode,uint8_t attr[35],uint16_t *lflags) {
168 	uint32_t h;
169 	double now;
170 	fdcacheentry *fdce,**fdcep;
171 
172 	now = monotonic_seconds();
173 	h = FDCACHE_HASH(inode);
174 	zassert(pthread_mutex_lock(hashlock+h));
175 	fdcep = fdhashtab + h;
176 	while ((fdce = *fdcep)) {
177 		if (fdce->inode==inode && fdce->uid==ctx->uid && fdce->gid==ctx->gid && fdce->pid==ctx->pid && fdce->createtime + FDCACHE_TIMEOUT >= now) {
178 			if (attr!=NULL) {
179 				memcpy(attr,fdce->attr,35);
180 			}
181 			if (lflags!=NULL) {
182 				*lflags = fdce->lflags;
183 			}
184 			*fdcep = fdce->next;
185 			zassert(pthread_mutex_unlock(hashlock+h));
186 			return fdce;
187 		} else {
188 			fdcep = &(fdce->next);
189 		}
190 	}
191 	zassert(pthread_mutex_unlock(hashlock+h));
192 	return NULL;
193 }
194 
fdcache_release(void * vfdce)195 void fdcache_release(void *vfdce) {
196 	fdcacheentry *fdce = (fdcacheentry*)vfdce;
197 
198 	if (fdce!=NULL) {
199 		fdcachee_free(fdce);
200 	}
201 }
202 
fdcache_inject_chunkdata(void * vfdce)203 void fdcache_inject_chunkdata(void *vfdce) {
204 	fdcacheentry *fdce = (fdcacheentry*)vfdce;
205 
206 	if ((fdce->lflags) & LOOKUP_CHUNK_ZERO_DATA) {
207 		chunksdatacache_insert(fdce->inode,0,fdce->chunkid,fdce->version,fdce->csdataver,fdce->csdata,fdce->csdatasize);
208 	}
209 }
210 
fdcache_init(void)211 void fdcache_init(void) {
212 	uint32_t i;
213 
214 	(void)fdcachee_free_all; // just calm down the compiler about unused functions
215 	(void)fdcachee_getusage;
216 
217 	for (i=0 ; i<FDCACHE_HASHSIZE ; i++) {
218 		fdhashtab[i] = NULL;
219 		zassert(pthread_mutex_init(hashlock+i,NULL));
220 	}
221 }
222