root/morphix/trunk/mini_fo/file.c

Revision 2, 28.5 kB (checked in by nextime, 2 years ago)

Initial import, branching from morphix svn

Line 
1 /*
2  * Copyright (c) 1997-2004 Erez Zadok <ezk@cs.stonybrook.edu>
3  * Copyright (c) 2001-2004 Stony Brook University
4  *
5  * For specific licensing information, see the COPYING file distributed with
6  * this package, or get one from ftp://ftp.filesystems.org/pub/fistgen/COPYING.
7  *
8  * This Copyright notice must be kept intact and distributed with all
9  * fistgen sources INCLUDING sources generated by fistgen.
10  */
11 /*
12  *  $Id: file.c 1364 2004-12-04 10:18:10Z alextreme $
13  *
14  * Parts of this file have been copied from mini_fo
15  * Copyright (C) 2004 Markus Klotzbuecher <mk@creamnet.de>
16  *
17  * MODIFICATIONS:
18  * 2004-08      Olivier Evalet  <evaleto at programmers dot ch>
19  *                      implemented fsync
20  *                      refactoring of readdir
21  */
22
23 #ifdef HAVE_CONFIG_H
24 # include <config.h>
25 #endif /* HAVE_CONFIG_H */
26 #ifdef FISTGEN
27 # include "fist_mini_fo.h"
28 #endif /* FISTGEN */
29 #include "fist.h"
30 #include "mini_fo.h"
31
32
33 /*******************
34  * File Operations *
35  *******************/
36
37
38 STATIC loff_t
39 mini_fo_llseek(file_t *file, loff_t offset, int origin)
40 {
41         loff_t err;
42         file_t *lower_file = NULL;
43
44         print_entry_location();
45         if(S_ISDIR(file->f_dentry->d_inode->i_mode)) {
46                 /* Check if trying to llseek from a directory */
47                 err = -EISDIR;
48                 goto out;
49         }
50         if (FILE_TO_PRIVATE(file) != NULL) {     // XXX: ZH: this is wrong?: in this case ASSERT is not in ifndef... Put ASSERT before the if statement, kill if statement
51                 lower_file = FILE_TO_LOWER_STO(file);
52                 if(!lower_file)
53                 lower_file = FILE_TO_LOWER(file);
54         }
55
56         fist_dprint(6, "mini_fo_llseek: file=%p, offset=0x%x, origin=%d\n",
57                     file, offset, origin);
58
59         ASSERT(lower_file != NULL);
60
61         /* always set lower position to this one */
62         lower_file->f_pos = file->f_pos;
63
64
65 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)
66         if (file->f_reada) { /* update readahead information if needed */
67                 lower_file->f_reada = file->f_reada;
68                 lower_file->f_ramax = file->f_ramax;
69                 lower_file->f_raend = file->f_raend;
70                 lower_file->f_ralen = file->f_ralen;
71                 lower_file->f_rawin = file->f_rawin;
72         }
73         ASSERT(lower_file->f_reada == file->f_reada);
74         ASSERT(lower_file->f_ramax == file->f_ramax);
75         ASSERT(lower_file->f_raend == file->f_raend);
76         ASSERT(lower_file->f_ralen == file->f_ralen);
77         ASSERT(lower_file->f_rawin == file->f_rawin);
78 #else
79         memcpy(&(lower_file->f_ra), &(file->f_ra), sizeof(struct file_ra_state)); // XXX: ZH: this a new structure.
80 #endif
81
82         if (lower_file->f_op && lower_file->f_op->llseek)
83                 err = lower_file->f_op->llseek(lower_file, offset, origin);
84         else
85                 err     = generic_file_llseek(lower_file, offset, origin);
86
87         if (err < 0)
88                 goto out;
89
90         if (err != file->f_pos) {
91                 file->f_pos = err;
92                 // ION maybe this?
93                 //      file->f_pos = lower_file->f_pos;
94 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)
95                 file->f_reada = 0;
96 #endif
97                 file->f_version ++ ;//
98         }
99 out:
100         print_exit_status(err);
101         return err;
102 }
103
104
105
106 STATIC ssize_t
107 mini_fo_read(file_t *file, char *buf, size_t count, loff_t *ppos)
108 {
109         int err = -EINVAL;
110         file_t *lower_file = NULL;
111         loff_t pos = *ppos;
112
113         print_entry_location();
114 //      printk ("file=%p count=%d pos=%p, pos=%d\n",file,count,ppos,*ppos);
115
116         if(S_ISDIR(file->f_dentry->d_inode->i_mode)) {
117                 /* Check if trying to read from a directory */
118                 /* printk(KERN_CRIT "mini_fo_read: ERROR: trying to read data from a directory.\n"); */
119                 err = -EISDIR;
120                 goto out;
121         }
122
123         if (FILE_TO_PRIVATE(file) != NULL){   // XXX: ZH: this is wrong?: in this case ASSERT is not in ifndef..Put ASSERT before the if statement, kill if statement
124                 lower_file = FILE_TO_LOWER_STO(file);
125                 if (!lower_file)
126                         lower_file = FILE_TO_LOWER(file);
127         }
128         ASSERT(lower_file != NULL);
129
130         if (!lower_file->f_op || !lower_file->f_op->read)
131                 goto out;
132
133         err = lower_file->f_op->read(lower_file, buf, count, &pos);
134
135         if (err >= 0) {
136                 /* atime should also be updated for reads of size zero or more */
137                 fist_copy_attr_atime(file->f_dentry->d_inode,
138                                      lower_file->f_dentry->d_inode);
139         }
140
141         // MAJOR HACK
142         /*
143          * because pread() does not have any way to tell us that it is
144          * our caller, then we don't know for sure if we have to update
145          * the file positions.  This hack relies on read() having passed us
146          * the "real" pointer of its struct file's f_pos field.
147          */
148        
149         /*
150          * oe: since the 2.6.8 the syscall as changed. !!FIXME!!
151          *     fs/read_write.c L283     
152          */
153         if (ppos == &file->f_pos)
154                 lower_file->f_pos = *ppos = pos;
155         else{
156                 lower_file->f_pos = *ppos = pos;
157         }
158
159 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)
160         if (lower_file->f_reada) { /* update readahead information if needed */
161                 file->f_reada = lower_file->f_reada;
162                 file->f_ramax = lower_file->f_ramax;
163                 file->f_raend = lower_file->f_raend;
164                 file->f_ralen = lower_file->f_ralen;
165                 file->f_rawin = lower_file->f_rawin;
166         }
167 #else
168         memcpy(&(file->f_ra), &(lower_file->f_ra), sizeof(struct file_ra_state));
169 #endif
170
171 out:
172         print_exit_status(err);
173         return err;
174 }
175
176
177 /* this mini_fo_write() does not modify data pages! */
178 STATIC ssize_t
179 mini_fo_write(file_t *file, const char *buf, size_t count, loff_t *ppos)
180 {
181         int err = -EINVAL;
182         file_t *lower_file = NULL;
183         inode_t *inode;
184         inode_t *lower_inode;
185         loff_t pos = *ppos;
186
187         print_entry_location();
188         if (FILE_TO_PRIVATE(file) != NULL){  // XXX: ZH: this is wrong?: in this case ASSERT is not in ifndef... Put ASSERT before the if statement, kill if statement
189                 lower_file = FILE_TO_LOWER_STO(file);
190                 if (!lower_file){
191                         /* This is bad! We have no storage file to write to. This should never
192                          * happen because if a file is opened for writing, a copy should have
193                          * been made earlier.
194                          */
195                         printk(KERN_CRIT "mini_fo: write : ERROR, no storage file to write.\n");
196                         err = -EPERM;
197                         goto out;
198                 }
199         }
200
201         inode = file->f_dentry->d_inode;
202         lower_inode = INODE_TO_LOWER_STO(inode);
203         if(!lower_inode) {
204                 printk(KERN_CRIT "mini_fo: write: no sto inode found, not good.\n");
205                 goto out;
206         }
207
208         if (!lower_file->f_op || !lower_file->f_op->write)
209                 goto out;
210
211         /* adjust for append -- seek to the end of the file */
212         if (file->f_flags & O_APPEND)
213                 pos = inode->i_size;
214
215         err = lower_file->f_op->write(lower_file, buf, count, &pos);
216
217         /*
218          * copy ctime and mtime from lower layer attributes
219          * atime is unchanged for both layers
220          */
221         if (err >= 0  )
222                 fist_copy_attr_times(inode, lower_inode);
223
224         /*
225          * XXX: MAJOR HACK
226          *
227          * because pwrite() does not have any way to tell us that it is
228          * our caller, then we don't know for sure if we have to update
229          * the file positions.  This hack relies on write() having passed us
230          * the "real" pointer of its struct file's f_pos field.
231          */
232        
233         /*
234          * oe: since the 2.6.9 the syscall as changed. !!FIXME!!
235          *     fs/read_write.c L301     
236          */
237        
238         if (ppos == &file->f_pos)
239                 lower_file->f_pos = *ppos = pos;
240         else
241                 lower_file->f_pos = *ppos = pos;
242
243         /* update this inode's size */
244         if (pos > inode->i_size)
245                 inode->i_size = pos;
246
247 out:
248         print_exit_status(err);
249         return err;
250 }
251
252
253 /* Global variable to hold a file_t pointer.
254  * This serves to allow mini_fo_filldir64 function to know which file is beeing
255  * read, which is required for two reasons:
256  *
257  *   - be able to call wol functions in order to avoid listing deleted base files.
258  *
259  *   - if we're reading a directory which is in state 1, we need to maintain a list
260  *     (in mini_fo_filldir64) of which files allready have been copied to userspace,
261  *     to detect files existing in base and storage and not list them twice.
262  */
263 STATIC file_t *mini_fo_filldir_file;
264
265 /* mainly copied from fs/readdir.c */
266 STATIC int
267 mini_fo_filldir64(void * __buf, const char * name, int namlen, loff_t offset,
268                   ino_t ino, unsigned int d_type)
269 {
270         struct linux_dirent64 * dirent, d;
271         struct mini_fo_getdents_callback * buf = (struct mini_fo_getdents_callback *) __buf;
272         int reclen, err;
273         file_t* file = buf->file;
274
275         /* check if we are merging the contents of storage and base */
276         if(file && DENTRY_TO_PRIVATE(file->f_dentry)->state == 1) {
277                 /* check if we are still reading storage contents, if
278                  * yes, we just save the name of the file for duplicate
279                  * checking later. */
280                 int tmp = strlen(WOL_FILENAME);
281                 if(tmp  == namlen) {
282                         if(!strncmp(name, WOL_FILENAME, namlen))
283                                 return 0;
284                 }
285
286                 if(!FILE_TO_PRIVATE(file)->rd.sto_done) {
287                         /* put file into ndl list */
288                         if(ndl_add_entry(&FILE_TO_PRIVATE(file)->rd, name, namlen))
289                                 printk(KERN_CRIT "mini_fo_filldir64: Error adding to ndl.\n");
290                 } else {
291                         /* check if file has been deleted */
292                         if(wol_check_entry(file->f_dentry->d_inode, name, namlen)) {
293                                 return 0;
294                         }
295                         /* do duplicate checking */
296                         if(ndl_check_entry(&FILE_TO_PRIVATE(file)->rd, name, namlen))
297                                 return 0;
298                 }
299         }
300
301 #if 0
302         reclen = ROUND_UP64(NAME_OFFSET(dirent) + namlen + 1);
303
304         buf->getdents->error = -EINVAL;/* only used if we fail.. */
305         if (reclen > buf->getdents->count)
306                 return -EINVAL;
307         dirent = buf->getdents->previous;
308         if (dirent) {
309                 d.d_off = offset;
310                 copy_to_user(&dirent->d_off, &d.d_off, sizeof(d.d_off));
311         }
312         dirent = buf->getdents->current_dir;
313         buf->getdents->previous = dirent;
314         memset(&d, 0, NAME_OFFSET(&d));
315         d.d_ino = ino;
316         d.d_reclen = reclen;
317         d.d_type = d_type;
318         copy_to_user(dirent, &d, NAME_OFFSET(&d));
319         copy_to_user(dirent->d_name, name, namlen);
320         put_user(0, dirent->d_name + namlen);
321         ((char *) dirent) += reclen;
322         //dirent=(struct linux_dirent64 *) ((char *) dirent) + reclen;
323         buf->getdents->current_dir = dirent;
324         buf->getdents->count -= reclen;
325         return 0;
326 #else
327         err = buf->filldir((void*)buf->getdents, name, namlen, offset, ino, d_type);
328         if (err >= 0) {
329                 buf->entries_written++;
330         }
331         return err;     
332        
333 #endif 
334 }
335
336
337
338 STATIC int
339 mini_fo_readdir(file_t *file, void *dirent, filldir_t filldir)
340 {
341         int err = 0;/* mk: ??? -ENOTDIR; */
342         file_t *lower_file = NULL;
343         file_t *lower_sto_file = NULL;
344         inode_t *inode;
345         int oldcount;
346
347 #if defined(FIST_FILTER_NAME) || defined(FIST_FILTER_SCA) || 1
348         struct mini_fo_getdents_callback buf;
349 #endif /* FIST_FILTER_NAME || FIST_FILTER_SCA */
350
351         print_entry_location();
352
353         buf.getdents= (struct getdents_callback64 *) dirent;
354         buf.file        = file;
355         buf.filldir     = filldir;
356        
357         oldcount = buf.getdents->count;
358         inode = file->f_dentry->d_inode;
359
360         FILE_TO_PRIVATE(file)->rd.sto_done = 0;
361         if (FILE_TO_PRIVATE(file) != NULL) {
362                 if(FILE_TO_LOWER_STO(file)) { /* && (FILE_TO_LOWER_STO(file)->f_pos < INODE_TO_LOWER_STO(inode)->i_size)) { */
363                         lower_sto_file = FILE_TO_LOWER_STO(file);
364                         err = vfs_readdir(lower_sto_file, mini_fo_filldir64, (void *) &buf);
365                         file->f_pos = lower_sto_file->f_pos;
366                         if (err > 0)
367                                 fist_copy_attr_atime(inode, lower_sto_file->f_dentry->d_inode);
368
369                 }
370                 FILE_TO_PRIVATE(file)->rd.sto_done = 1;
371
372                 if(FILE_TO_LOWER(file)) { /* && (FILE_TO_LOWER(file)->f_pos < INODE_TO_LOWER(inode)->i_size)) { */
373                         lower_file = FILE_TO_LOWER(file);
374                         err = vfs_readdir(lower_file, mini_fo_filldir64, (void *) &buf);
375                         file->f_pos = lower_file->f_pos;
376                         if (err > 0)
377                                 fist_copy_attr_atime(inode, lower_file->f_dentry->d_inode);
378                 }
379         }
380         /* mk:
381          * we need to check if all the directory data has been copied to userspace,
382          * or if we will be called again by userspace to complete the operation.
383          */
384         if(buf.getdents->count == oldcount) {
385                 ndl_put_list(&FILE_TO_PRIVATE(file)->rd);
386         }
387
388         fist_checkinode(inode, "post mini_fo_readdir");
389         print_exit_status(err);
390
391         /* unset this, safe */
392         mini_fo_filldir_file = NULL;   
393         return err;
394 }
395
396
397 STATIC unsigned int
398 mini_fo_poll(file_t *file, poll_table *wait)
399 {
400         unsigned int mask = DEFAULT_POLLMASK;
401         file_t *lower_file = NULL;
402
403         print_entry_location();
404         if (FILE_TO_PRIVATE(file) != NULL){  // XXX: ZH: this is wrong?: in this case ASSERT is not in ifndef... Put ASSERT before the if statement, kill if statement         
405                 if(DENTRY_TO_PRIVATE(file->f_dentry)->state == STATE_FILE_UNMODIFIED) {
406                         lower_file = FILE_TO_LOWER(file);
407                 }else{
408                         lower_file = FILE_TO_LOWER_STO(file);
409                 }                       
410
411         }
412         ASSERT(lower_file != NULL);
413
414         if (!lower_file->f_op || !lower_file->f_op->poll)
415                 goto out;
416
417         mask = lower_file->f_op->poll(lower_file, wait);
418
419 out:
420         print_exit_status(mask);
421         return mask;
422 }
423
424
425 STATIC int
426 mini_fo_ioctl(inode_t *inode, file_t *file, unsigned int cmd, unsigned long arg)
427 {
428         int err = 0;            /* don't fail by default */
429         file_t *lower_file = NULL;
430         vfs_t *this_vfs;
431         vnode_t *this_vnode;
432         int val;
433 #ifdef FIST_COUNT_WRITES
434         extern unsigned long count_writes, count_writes_middle;
435 #endif /* FIST_COUNT_WRITES */
436
437         print_entry_location();
438
439         this_vfs = inode->i_sb;
440         this_vnode = inode;
441
442         /* check if asked for local commands */
443         switch (cmd) {
444         case FIST_IOCTL_GET_DEBUG_VALUE:
445                 val = fist_get_debug_value();
446                 printk("IOCTL GET: send arg %d\n", val);
447                 err = put_user(val, (int *) arg);
448 #ifdef FIST_COUNT_WRITES
449                 printk("COUNT_WRITES:%lu:%lu\n", count_writes, count_writes_middle);
450 #endif /* FIST_COUNT_WRITES */
451                 break;
452
453         case FIST_IOCTL_SET_DEBUG_VALUE:
454                 err = get_user(val, (int *) arg);
455                 if (err)
456                         break;
457                 fist_dprint(6, "IOCTL SET: got arg %d\n", val);
458                 if (val < 0 || val > 20) {
459                         err = -EINVAL;
460                         break;
461                 }
462                 fist_set_debug_value(val);
463                 break;
464
465                 /* add non-debugging fist ioctl's here */
466                
467
468     default:
469                 if (FILE_TO_PRIVATE(file) != NULL) {     // XXX: ZH: this is wrong?: in this case ASSERT is not in ifndef... Put ASSERT before the if statement, kill if statement
470                         lower_file = FILE_TO_LOWER(file);
471                 }
472                 /* pass operation to lower filesystem, and return status */
473                 if (lower_file && lower_file->f_op && lower_file->f_op->ioctl)
474                         err = lower_file->f_op->ioctl(INODE_TO_LOWER(inode), lower_file, cmd, arg);
475                 else
476                         err     = -ENOTTY;      /* this is an unknown ioctl */
477         } /* end of outer switch statement */
478
479         print_exit_status(err);
480         return err;
481 }
482
483
484 /* FIST-LITE special version of mmap */
485 STATIC int
486 mini_fo_mmap(file_t *file, vm_area_t *vma)
487 {
488         int err = 0;
489         file_t *lower_file = NULL;
490         inode_t *inode;
491         inode_t *lower_inode;
492
493         print_entry_location();
494         if (FILE_TO_PRIVATE(file) != NULL){   // XXX: ZH: this is wrong?: WHERE IS ASSERT IN THIS CASE??? Put ASSERT before the if statement, kill if statement
495                 lower_file = FILE_TO_LOWER_STO(file);
496                 if (!lower_file)
497                         lower_file = FILE_TO_LOWER(file);
498         }
499
500         ASSERT(lower_file != NULL);
501         ASSERT(lower_file->f_op != NULL);
502         if (lower_file->f_op->mmap == NULL) {
503             err = -1;
504             return err;
505         }
506 // These ASSERT's are insane: they don't abort and aren't used to abort!
507         
508         ASSERT(lower_file->f_op->mmap != NULL);
509
510         vma->vm_file