Version increased to unfs3_0.9.22+dfsg-1maemo3
[unfs3] / unfs3 / fd_cache.c
1
2 /*
3  * UNFS3 file descriptor cache
4  * (C) 2004, Pascal Schmidt
5  * see file LICENSE for license details
6  */
7
8 #include "config.h"
9
10 #include <sys/types.h>
11 #include <sys/stat.h>
12 #include <rpc/rpc.h>
13 #include <errno.h>
14 #include <fcntl.h>
15 #include <limits.h>
16 #include <time.h>
17 #ifndef WIN32
18 #include <syslog.h>
19 #include <unistd.h>
20 #endif                                 /* WIN32 */
21
22 #include "nfs.h"
23 #include "mount.h"
24 #include "fh.h"
25 #include "daemon.h"
26 #include "Config/exports.h"
27 #include "fd_cache.h"
28 #include "backend.h"
29
30 /*
31  * intention of the file descriptor cache
32  *
33  * for READ operations, the intent is to open() the file on the first
34  * access and to close() it when we hit EOF or after two seconds of
35  * inactivity.
36  *
37  * for WRITE operations, the intent is to open() the file on the first
38  * UNSTABLE access and to close() it when COMMIT is called or after
39  * two seconds of inactivity. 
40  * 
41  * There are three states of an entry:
42  * 1) Unused. use == 0. 
43  * 2) Open fd. use != 0, fd != -1. 
44  * 3) Pending fsync/close error, to be reported in next COMMIT or WRITE. use != 0, fd == -1. 
45  *
46  * Handling fsync/close errors 100% correctly is very difficult for a
47  * user space server. Although rare, fsync/close might fail, for
48  * example when out of quota or closing a file on a NFS file
49  * system. The most correct way of handling these errors would be to
50  * keep track of "dirty" and failed ranges. However, this would
51  * require runtime memory allocation, with no known upper bound, which
52  * in turn can lead to DOS attacks etc. Our solution returns a
53  * fsync/close error in the first WRITE or COMMIT
54  * response. Additionally, the write verifier is changed. Subsequent
55  * COMMITs may succeed even though data has been lost, but since the
56  * verifier is changed, clients will notice this and re-send their
57  * data. Eventually, with some luck, all clients will get an IO error.
58  */
59
60 /* number of entries in fd cache */
61 #define FD_ENTRIES      256
62
63 /* The number of seconds to wait before closing inactive fd */
64 #define INACTIVE_TIMEOUT 2
65
66 /* The number of seconds to keep pending errors */
67 #define PENDING_ERROR_TIMEOUT 7200     /* 2 hours */
68
69 typedef struct {
70     int fd;                     /* open file descriptor */
71     int kind;                   /* read or write */
72     time_t use;                 /* last use */
73     uint32 dev;                 /* device */
74     uint64 ino;                 /* inode */
75     uint32 gen;                 /* inode generation */
76 } fd_cache_t;
77
78 static fd_cache_t fd_cache[FD_ENTRIES];
79
80 /* statistics */
81 int fd_cache_readers = 0;
82 int fd_cache_writers = 0;
83
84 /*
85  * initialize the fd cache
86  */
87 void fd_cache_init(void)
88 {
89     int i;
90
91     for (i = 0; i < FD_ENTRIES; i++) {
92         fd_cache[i].fd = -1;
93         fd_cache[i].kind = UNFS3_FD_READ;
94         fd_cache[i].use = 0;
95         fd_cache[i].dev = 0;
96         fd_cache[i].ino = 0;
97         fd_cache[i].gen = 0;
98     }
99 }
100
101 /*
102  * find cache index to use for new entry
103  * returns an empty slot if found, else return error
104  */
105 static int fd_cache_unused(void)
106 {
107     int i;
108     static time_t last_warning = 0;
109
110     for (i = 0; i < FD_ENTRIES; i++) {
111         if (fd_cache[i].use == 0)
112             return i;
113     }
114
115     /* Do not print warning more than once per 10 second */
116     if (time(NULL) > last_warning + 10) {
117         last_warning = time(NULL);
118         logmsg(LOG_INFO,
119                "fd cache full due to more than %d active files or pending IO errors",
120                FD_ENTRIES);
121     }
122
123     return -1;
124 }
125
126 /*
127
128  * remove an entry from the cache. The keep_on_error variable
129  * indicates if the entry should be kept in the cache upon
130  * fsync/close failures. It should be set to TRUE when fd_cache_del is
131  * called from a code path which cannot report an IO error back to the
132  * client through WRITE or COMMIT. 
133  */
134 static int fd_cache_del(int idx, int keep_on_error)
135 {
136     int res1, res2;
137
138     res1 = -1;
139
140     if (fd_cache[idx].fd != -1) {
141         if (fd_cache[idx].kind == UNFS3_FD_WRITE) {
142             /* sync file data if writing descriptor */
143             fd_cache_writers--;
144             res1 = backend_fsync(fd_cache[idx].fd);
145         } else {
146             fd_cache_readers--;
147             res1 = 0;
148         }
149         res2 = backend_close(fd_cache[idx].fd);
150         fd_cache[idx].fd = -1;
151
152         /* return -1 if something went wrong during sync or close */
153         if (res1 == -1 || res2 == -1) {
154             res1 = -1;
155         }
156     } else
157         /* pending error */
158         errno = EIO;
159
160     if (res1 == -1 && !keep_on_error) {
161         /* The verifier should not be changed until we actually report &
162            remove the error */
163         regenerate_write_verifier();
164     }
165
166     if (res1 != -1 || !keep_on_error) {
167         fd_cache[idx].fd = -1;
168         fd_cache[idx].use = 0;
169         fd_cache[idx].dev = 0;
170         fd_cache[idx].ino = 0;
171         fd_cache[idx].gen = 0;
172     }
173
174     return res1;
175 }
176
177 /*
178  * add an entry to the cache
179  */
180 static void fd_cache_add(int fd, unfs3_fh_t * ufh, int kind)
181 {
182     int idx;
183
184     idx = fd_cache_unused();
185     if (idx != -1) {
186         /* update statistics */
187         if (kind == UNFS3_FD_READ)
188             fd_cache_readers++;
189         else
190             fd_cache_writers++;
191
192         fd_cache[idx].fd = fd;
193         fd_cache[idx].kind = kind;
194         fd_cache[idx].use = time(NULL);
195         fd_cache[idx].dev = ufh->dev;
196         fd_cache[idx].ino = ufh->ino;
197         fd_cache[idx].gen = ufh->gen;
198     }
199 }
200
201 /*
202  * find entry by operating system fd number
203  */
204 static int idx_by_fd(int fd, int kind)
205 {
206     int i;
207     int idx = -1;
208
209     for (i = 0; i < FD_ENTRIES; i++)
210         if (fd_cache[i].fd == fd && fd_cache[i].kind == kind) {
211             idx = i;
212             break;
213         }
214     return idx;
215 }
216
217 /*
218  * find entry by fh (device, inode, and generation number)
219  */
220 static int idx_by_fh(unfs3_fh_t * ufh, int kind)
221 {
222     int i;
223     int idx = -1;
224
225     for (i = 0; i < FD_ENTRIES; i++)
226         if (fd_cache[i].kind == kind) {
227             if (fd_cache[i].dev == ufh->dev && fd_cache[i].ino == ufh->ino &&
228                 fd_cache[i].gen == ufh->gen) {
229                 idx = i;
230                 break;
231             }
232         }
233     return idx;
234 }
235
236 /*
237  * open a file descriptor
238  * uses fd from cache if possible
239  */
240 int fd_open(const char *path, nfs_fh3 nfh, int kind, int allow_caching)
241 {
242     int idx, res, fd;
243     backend_statstruct buf;
244     unfs3_fh_t *fh = (void *) nfh.data.data_val;
245
246     idx = idx_by_fh(fh, kind);
247
248     if (idx != -1) {
249         if (fd_cache[idx].fd == -1) {
250             /* pending error, report to client and remove from cache */
251             fd_cache_del(idx, FALSE);
252             return -1;
253         }
254         return fd_cache[idx].fd;
255     } else {
256         /* call open to obtain new fd */
257         if (kind == UNFS3_FD_READ)
258             fd = backend_open(path, O_RDONLY);
259         else
260             fd = backend_open(path, O_WRONLY);
261         if (fd == -1)
262             return -1;
263
264         /* check for local fs race */
265         res = backend_fstat(fd, &buf);
266         if ((res == -1) ||
267             (fh->dev != buf.st_dev || fh->ino != buf.st_ino ||
268              fh->gen != backend_get_gen(buf, fd, path))) {
269             /* 
270              * local fs changed meaning of path between
271              * calling NFS operation doing fh_decomp and
272              * arriving here
273              *
274              * set errno to ELOOP to make calling NFS
275              * operation return NFS3ERR_STALE
276              */
277             backend_close(fd);
278             errno = ELOOP;
279             return -1;
280         }
281
282         /* 
283          * success, add to cache for later use
284          */
285         if (allow_caching)
286             fd_cache_add(fd, fh, kind);
287         return fd;
288     }
289 }
290
291 /*
292  * close a file descriptor
293  * returns error number from real close() if applicable
294  */
295 int fd_close(int fd, int kind, int really_close)
296 {
297     int idx, res1 = 0, res2 = 0;
298
299     idx = idx_by_fd(fd, kind);
300     if (idx != -1) {
301         /* update usage time of cache entry */
302         fd_cache[idx].use = time(NULL);
303
304         if (really_close == FD_CLOSE_REAL)
305             /* delete entry on real close, will close() fd */
306             return fd_cache_del(idx, FALSE);
307         else
308             return 0;
309     } else {
310         /* not in cache, sync and close directly */
311         if (kind == UNFS3_FD_WRITE)
312             res1 = backend_fsync(fd);
313
314         res2 = backend_close(fd);
315
316         if (res1 != 0)
317             return res1;
318         else
319             return res2;
320     }
321 }
322
323 /*
324  * sync file descriptor data to disk
325  */
326 int fd_sync(nfs_fh3 nfh)
327 {
328     int idx;
329     unfs3_fh_t *fh = (void *) nfh.data.data_val;
330
331     idx = idx_by_fh(fh, UNFS3_FD_WRITE);
332     if (idx != -1)
333         /* delete entry, will fsync() and close() the fd */
334         return fd_cache_del(idx, FALSE);
335     else
336         return 0;
337 }
338
339 /*
340  * purge/shutdown the cache
341  */
342 void fd_cache_purge(void)
343 {
344     int i;
345
346     /* close any open file descriptors we still have */
347     for (i = 0; i < FD_ENTRIES; i++) {
348         if (fd_cache[i].use != 0) {
349             if (fd_cache_del(i, TRUE) == -1)
350                 logmsg(LOG_CRIT,
351                        "Error during shutdown fsync/close for dev %lu, inode %lu",
352                        fd_cache[i].dev, fd_cache[i].ino);
353
354         }
355     }
356 }
357
358 /*
359  * close inactive fds
360  */
361 void fd_cache_close_inactive(void)
362 {
363     time_t now;
364     int i;
365     int found_error = 0;
366     int active_error = 0;
367
368     now = time(NULL);
369     for (i = 0; i < FD_ENTRIES; i++) {
370         /* Check for inactive open fds */
371         if (fd_cache[i].use && fd_cache[i].fd != -1 &&
372             fd_cache[i].use + INACTIVE_TIMEOUT < now) {
373             fd_cache_del(i, TRUE);
374         }
375
376         /* Check for inactive pending errors */
377         if (fd_cache[i].use && fd_cache[i].fd == -1) {
378             found_error = 1;
379             if (fd_cache[i].use + PENDING_ERROR_TIMEOUT > now)
380                 active_error = 1;
381         }
382     }
383
384     if (found_error && !active_error) {
385         /* All pending errors are old. Delete them all from the table and
386            generate new verifier. This is done to prevent the table from
387            filling up with old pending errors, perhaps for files that never
388            will be written again. In this case, we throw away the errors, and 
389            change the server verifier. If clients has pending COMMITs, they
390            will notify the changed verifier and re-send. */
391         for (i = 0; i < FD_ENTRIES; i++) {
392             if (fd_cache[i].use && fd_cache[i].fd == -1) {
393                 fd_cache_del(i, FALSE);
394             }
395         }
396         regenerate_write_verifier();
397     }
398 }