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