- port, cleanup Emulab ICMP Ping Of Death (IPOD) patch from 2.4.x
[linux-2.6.git] / fs / hostfs / externfs.c
1 /* 
2  * Copyright (C) 2000 - 2004 Jeff Dike (jdike@addtoit.com)
3  * Licensed under the GPL
4  */
5
6 #include <linux/stddef.h>
7 #include <linux/fs.h>
8 #include <linux/version.h>
9 #include <linux/module.h>
10 #include <linux/init.h>
11 #include <linux/slab.h>
12 #include <linux/pagemap.h>
13 #include <linux/blkdev.h>
14 #include <linux/statfs.h>
15 #include <asm/uaccess.h>
16 #include "hostfs.h"
17 #include "kern_util.h"
18 #include "kern.h"
19 #include "user_util.h"
20 #include "2_5compat.h"
21 #include "mem.h"
22 #include "filehandle.h"
23
24 struct externfs {
25         struct list_head list;
26         struct externfs_mount_ops *mount_ops;
27         struct file_system_type type;
28 };
29
30 static inline struct externfs_inode *EXTERNFS_I(struct inode *inode)
31 {
32         return(container_of(inode, struct externfs_inode, vfs_inode));
33 }
34
35 #define file_externfs_i(file) EXTERNFS_I((file)->f_dentry->d_inode)
36
37 int externfs_d_delete(struct dentry *dentry)
38 {
39         return(1);
40 }
41
42 struct dentry_operations externfs_dentry_ops = {
43 };
44
45 #define EXTERNFS_SUPER_MAGIC 0x00c0ffee
46
47 static struct inode_operations externfs_iops;
48 static struct inode_operations externfs_dir_iops;
49 static struct address_space_operations externfs_link_aops;
50
51 static char *dentry_name(struct dentry *dentry, int extra)
52 {
53         struct dentry *parent;
54         char *name;
55         int len;
56
57         len = 0;
58         parent = dentry;
59         while(parent->d_parent != parent){
60                 len += parent->d_name.len + 1;
61                 parent = parent->d_parent;
62         }
63         
64         name = kmalloc(len + extra + 1, GFP_KERNEL);
65         if(name == NULL) return(NULL);
66
67         name[len] = '\0';
68         parent = dentry;
69         while(parent->d_parent != parent){
70                 len -= parent->d_name.len + 1;
71                 name[len] = '/';
72                 strncpy(&name[len + 1], parent->d_name.name, 
73                         parent->d_name.len);
74                 parent = parent->d_parent;
75         }
76
77         return(name);
78 }
79
80 char *inode_name(struct inode *ino, int extra)
81 {
82         struct dentry *dentry;
83
84         dentry = list_entry(ino->i_dentry.next, struct dentry, d_alias);
85         return(dentry_name(dentry, extra));
86 }
87
88 char *inode_name_prefix(struct inode *inode, char *prefix)
89 {
90         int len;
91         char *name;
92
93         len = strlen(prefix);
94         name = inode_name(inode, len);
95         if(name == NULL)
96                 return(name);
97
98         memmove(&name[len], name, strlen(name) + 1);
99         memcpy(name, prefix, strlen(prefix));
100         return(name);
101 }
102
103 static int read_name(struct inode *ino, char *name)
104 {
105         struct externfs_file_ops *ops = EXTERNFS_I(ino)->ops;
106         /* The non-int inode fields are copied into ints by stat_file and
107          * then copied into the inode because passing the actual pointers
108          * in and having them treated as int * breaks on big-endian machines
109          */
110         dev_t i_rdev;
111         int err;
112         int i_mode, i_nlink, i_blksize;
113         unsigned long atime, mtime, ctime;
114         unsigned long long i_size;
115         unsigned long long i_ino;
116         unsigned long long i_blocks;
117
118         err = (*ops->stat_file)(name, ino->i_sb->s_fs_info, &i_rdev, &i_ino,
119                                 &i_mode, &i_nlink, &ino->i_uid, &ino->i_gid,
120                                 &i_size, &atime, &mtime, &ctime, &i_blksize, 
121                                 &i_blocks);
122         if(err) return(err);
123
124         ino->i_atime.tv_sec = atime;
125         ino->i_atime.tv_nsec = 0;
126         
127         ino->i_ctime.tv_sec = ctime;
128         ino->i_ctime.tv_nsec = 0;
129         
130         ino->i_mtime.tv_sec = mtime;
131         ino->i_mtime.tv_nsec = 0;
132
133         ino->i_ino = i_ino;
134         ino->i_rdev = i_rdev;
135         ino->i_mode = i_mode;
136         ino->i_nlink = i_nlink;
137         ino->i_size = i_size;
138         ino->i_blksize = i_blksize;
139         ino->i_blocks = i_blocks;
140         return(0);
141 }
142
143 static char *follow_link(char *link, 
144                          int (*do_read_link)(char *path, int uid, int gid,
145                                              char *buf, int size, 
146                                              struct externfs_data *ed),
147                          int uid, int gid, struct externfs_data *ed)
148 {
149         int len, n;
150         char *name, *resolved, *end;
151
152         len = 64;
153         while(1){
154                 n = -ENOMEM;
155                 name = kmalloc(len, GFP_KERNEL);
156                 if(name == NULL)
157                         goto out;
158
159                 n = (*do_read_link)(link, uid, gid, name, len, ed);
160                 if(n < len)
161                         break;
162                 len *= 2;
163                 kfree(name);
164         }
165         if(n < 0)
166                 goto out_free;
167
168         if(*name == '/')
169                 return(name);
170
171         end = strrchr(link, '/');
172         if(end == NULL)
173                 return(name);
174
175         *(end + 1) = '\0';
176         len = strlen(link) + strlen(name) + 1;
177
178         resolved = kmalloc(len, GFP_KERNEL);
179         if(resolved == NULL){
180                 n = -ENOMEM;
181                 goto out_free;
182         }
183
184         sprintf(resolved, "%s%s", link, name);
185         kfree(name);
186         return(resolved);
187
188  out_free:
189         kfree(name);
190  out:
191         return(ERR_PTR(n));
192 }
193
194 static int read_inode(struct inode *ino)
195 {
196         struct externfs_file_ops *ops = EXTERNFS_I(ino)->ops;
197         struct externfs_data *ed = ino->i_sb->s_fs_info;
198         char *name, *new;
199         int err = 0, type;
200
201         /* Unfortunately, we are called from iget() when we don't have a dentry
202          * allocated yet.
203          */
204         if(list_empty(&ino->i_dentry))
205                 goto out;
206  
207         err = -ENOMEM;
208         name = inode_name(ino, 0);
209         if(name == NULL) 
210                 goto out;
211
212         type = (*ops->file_type)(name, NULL, ed);
213         if(type < 0){
214                 err = type;
215                 goto out_free;
216         }
217
218         if(type == OS_TYPE_SYMLINK){
219                 new = follow_link(name, ops->read_link, current->fsuid,
220                                   current->fsgid, ed);
221                 if(IS_ERR(new)){
222                         err = PTR_ERR(new);
223                         goto out_free;
224                 }
225                 kfree(name);
226                 name = new;
227         }
228         
229         err = read_name(ino, name);
230  out_free:
231         kfree(name);
232  out:
233         return(err);
234 }
235
236 int externfs_statfs(struct super_block *sb, struct kstatfs *sf)
237 {
238         /* do_statfs uses struct statfs64 internally, but the linux kernel
239          * struct statfs still has 32-bit versions for most of these fields,
240          * so we convert them here
241          */
242         int err;
243         long long f_blocks;
244         long long f_bfree;
245         long long f_bavail;
246         long long f_files;
247         long long f_ffree;
248         struct externfs_data *ed = sb->s_fs_info;
249         
250         err = (*ed->file_ops->statfs)(&sf->f_bsize, &f_blocks, &f_bfree, 
251                                       &f_bavail, &f_files, &f_ffree, 
252                                       &sf->f_fsid, sizeof(sf->f_fsid), 
253                                       &sf->f_namelen, sf->f_spare, ed);
254         if(err)
255                 return(err);
256
257         sf->f_blocks = f_blocks;
258         sf->f_bfree = f_bfree;
259         sf->f_bavail = f_bavail;
260         sf->f_files = f_files;
261         sf->f_ffree = f_ffree;
262         sf->f_type = EXTERNFS_SUPER_MAGIC;
263         return(0);
264 }
265
266 static struct inode *externfs_alloc_inode(struct super_block *sb)
267 {
268         struct externfs_data *ed = sb->s_fs_info;
269         struct externfs_inode *ext;
270
271         ext = (*ed->mount_ops->init_file)(ed);
272         if(ext == NULL) 
273                 return(NULL);
274
275         *ext = ((struct externfs_inode) { .ops  = ed->file_ops });
276
277         inode_init_once(&ext->vfs_inode);
278         return(&ext->vfs_inode);
279 }
280
281 static void externfs_destroy_inode(struct inode *inode)
282 {
283         struct externfs_inode *ext = EXTERNFS_I(inode);
284
285         (*ext->ops->close_file)(ext, inode->i_size);
286 }
287
288 static void externfs_read_inode(struct inode *inode)
289 {
290         read_inode(inode);
291 }
292
293 static struct super_operations externfs_sbops = { 
294         .alloc_inode    = externfs_alloc_inode,
295         .destroy_inode  = externfs_destroy_inode,
296         .read_inode     = externfs_read_inode,
297         .statfs         = externfs_statfs,
298 };
299
300 int externfs_readdir(struct file *file, void *ent, filldir_t filldir)
301 {
302         void *dir;
303         char *name;
304         unsigned long long next, ino;
305         int error, len;
306         struct externfs_file_ops *ops = file_externfs_i(file)->ops;
307         struct externfs_data *ed = file->f_dentry->d_inode->i_sb->s_fs_info;
308
309         name = dentry_name(file->f_dentry, 0);
310         if(name == NULL) 
311                 return(-ENOMEM);
312
313         dir = (*ops->open_dir)(name, current->fsuid, current->fsgid, ed);
314         kfree(name);
315         if(IS_ERR(dir)) 
316                 return(PTR_ERR(dir));
317
318         next = file->f_pos;
319         while((name = (*ops->read_dir)(dir, &next, &ino, &len, ed)) != NULL){
320                 error = (*filldir)(ent, name, len, file->f_pos, ino, 
321                                    DT_UNKNOWN);
322                 if(error) 
323                         break;
324                 file->f_pos = next;
325         }
326         (*ops->close_dir)(dir, ed);
327         return(0);
328 }
329
330 int externfs_file_open(struct inode *ino, struct file *file)
331 {
332         ino->i_nlink++;
333         return(0);
334 }
335
336 int externfs_fsync(struct file *file, struct dentry *dentry, int datasync)
337 {
338         struct externfs_file_ops *ops = file_externfs_i(file)->ops;
339         struct inode *inode = dentry->d_inode;
340         struct externfs_data *ed = inode->i_sb->s_fs_info;
341
342         return((*ops->truncate_file)(EXTERNFS_I(inode), inode->i_size, ed));
343 }
344
345 static struct file_operations externfs_file_fops = {
346         .llseek         = generic_file_llseek,
347         .read           = generic_file_read,
348         .write          = generic_file_write,
349         .mmap           = generic_file_mmap,
350         .open           = externfs_file_open,
351         .release        = NULL,
352         .fsync          = externfs_fsync,
353 };
354
355 static struct file_operations externfs_dir_fops = {
356         .readdir        = externfs_readdir,
357         .read           = generic_read_dir,
358 };
359
360 struct wp_info {
361         struct page *page;
362         int count;
363         unsigned long long start;
364         unsigned long long size;
365         int (*truncate)(struct externfs_inode *ext, __u64 size, 
366                         struct externfs_data *ed);
367         struct externfs_inode *ei;
368         struct externfs_data *ed;
369 };
370
371 static void externfs_finish_writepage(char *buffer, int res, void *arg)
372 {
373         struct wp_info *wp = arg;
374
375         if(res == wp->count){
376                 ClearPageError(wp->page);
377                 if(wp->start + res > wp->size)
378                         (*wp->truncate)(wp->ei, wp->size, wp->ed);
379         }
380         else {
381                 SetPageError(wp->page);
382                 ClearPageUptodate(wp->page);
383         }               
384
385         kunmap(wp->page);
386         unlock_page(wp->page);
387         kfree(wp);
388 }
389
390 int externfs_writepage(struct page *page, struct writeback_control *wbc)
391 {
392         struct address_space *mapping = page->mapping;
393         struct inode *inode = mapping->host;
394         struct externfs_file_ops *ops = EXTERNFS_I(inode)->ops;
395         struct wp_info *wp;
396         struct externfs_data *ed = inode->i_sb->s_fs_info;
397         char *buffer;
398         unsigned long long base;
399         int count = PAGE_CACHE_SIZE;
400         int end_index = inode->i_size >> PAGE_CACHE_SHIFT;
401         int err, offset;
402
403         base = ((unsigned long long) page->index) << PAGE_CACHE_SHIFT;
404
405         /* If we are entirely outside the file, then return an error */
406         err = -EIO;
407         offset = inode->i_size & (PAGE_CACHE_SIZE-1);
408         if (page->index > end_index || 
409             ((page->index == end_index) && !offset))
410                 goto out_unlock;
411
412         err = -ENOMEM;
413         wp = kmalloc(sizeof(*wp), GFP_KERNEL);
414         if(wp == NULL)
415                 goto out_unlock;
416
417         *wp = ((struct wp_info) { .page         = page,
418                                   .count        = count,
419                                   .start        = base,
420                                   .size         = inode->i_size,
421                                   .truncate     = ops->truncate_file,
422                                   .ei           = EXTERNFS_I(inode),
423                                   .ed           = ed });
424
425         buffer = kmap(page);
426         err = (*ops->write_file)(EXTERNFS_I(inode), base, buffer, 0, 
427                                  count, externfs_finish_writepage, wp, ed);
428
429         return err;
430
431  out_unlock:
432         unlock_page(page);
433         return(err);
434 }
435
436 static void externfs_finish_readpage(char *buffer, int res, void *arg)
437 {
438         struct page *page = arg;
439         struct inode *inode;
440
441         if(res < 0){
442                 SetPageError(page);
443                 goto out;
444         }
445
446         inode = page->mapping->host;
447         if(inode->i_size >> PAGE_CACHE_SHIFT == page->index)
448                 res = inode->i_size % PAGE_CACHE_SIZE;
449
450         memset(&buffer[res], 0, PAGE_CACHE_SIZE - res);
451
452         flush_dcache_page(page);
453         SetPageUptodate(page);
454         if (PageError(page)) 
455                 ClearPageError(page);
456  out:
457         kunmap(page);
458         unlock_page(page);
459 }
460
461 static int externfs_readpage(struct file *file, struct page *page)
462 {
463         struct inode *ino = page->mapping->host;
464         struct externfs_file_ops *ops = EXTERNFS_I(ino)->ops;
465         struct externfs_data *ed = ino->i_sb->s_fs_info;
466         char *buffer;
467         long long start;
468         int err = 0;
469
470         start = (long long) page->index << PAGE_CACHE_SHIFT;
471         buffer = kmap(page);
472
473         if(ops->map_file_page != NULL){
474                 /* XXX What happens when PAGE_SIZE != PAGE_CACHE_SIZE? */
475                 err = (*ops->map_file_page)(file_externfs_i(file), start, 
476                                             buffer, file->f_mode & FMODE_WRITE,
477                                             ed);
478                 if(!err)
479                         err = PAGE_CACHE_SIZE;
480         }
481         else err = (*ops->read_file)(file_externfs_i(file), start, buffer,
482                                      PAGE_CACHE_SIZE, 0, 0, 
483                                      externfs_finish_readpage, page, ed);
484
485         if(err > 0)
486                 err = 0;
487         return(err);
488 }
489
490 struct writepage_info {
491         struct semaphore sem;
492         int res;
493 };
494
495 static void externfs_finish_prepare(char *buffer, int res, void *arg)
496 {
497         struct writepage_info *wp = arg;
498
499         wp->res = res;
500         up(&wp->sem);
501 }
502
503 int externfs_prepare_write(struct file *file, struct page *page, 
504                          unsigned int from, unsigned int to)
505 {
506         struct address_space *mapping = page->mapping;
507         struct inode *inode = mapping->host;
508         struct externfs_file_ops *ops = EXTERNFS_I(inode)->ops;
509         struct externfs_data *ed = inode->i_sb->s_fs_info;
510         char *buffer;
511         long long start;
512         int err;
513         struct writepage_info wp;
514
515         if(PageUptodate(page))
516                 return(0);
517
518         start = (long long) page->index << PAGE_CACHE_SHIFT;
519         buffer = kmap(page);
520
521         if(ops->map_file_page != NULL){
522                 err = (*ops->map_file_page)(file_externfs_i(file), start, 
523                                             buffer, file->f_mode & FMODE_WRITE,
524                                             ed);
525                 goto out;
526                 
527         }
528
529         init_MUTEX_LOCKED(&wp.sem);
530         err = (*ops->read_file)(file_externfs_i(file), start, buffer,
531                                 PAGE_CACHE_SIZE, from, to, 
532                                 externfs_finish_prepare, &wp, ed);
533         down(&wp.sem);
534         if(err < 0) 
535                 goto out;
536
537         err = wp.res;
538         if(err < 0)
539                 goto out;
540
541         if(from > 0)
542                 memset(buffer, 0, from);
543         if(to < PAGE_CACHE_SIZE)
544                 memset(buffer + to, 0, PAGE_CACHE_SIZE - to);
545
546         SetPageUptodate(page);
547         err = 0;
548  out:
549         kunmap(page);
550         return(err);
551 }
552
553 static int externfs_commit_write(struct file *file, struct page *page, 
554                                unsigned from, unsigned to)
555 {
556         struct address_space *mapping = page->mapping;
557         struct inode *inode = mapping->host;
558         struct externfs_file_ops *ops = EXTERNFS_I(inode)->ops;
559         unsigned long long size;
560         long long start;
561         int err;
562
563         start = (long long) (page->index << PAGE_CACHE_SHIFT);
564
565         if(ops->map_file_page != NULL)
566                 err = to - from;
567         else {
568                 size = start + to;
569                 if(size > inode->i_size){
570                         inode->i_size = size;
571                         mark_inode_dirty(inode);
572                 }
573         }
574
575         set_page_dirty(page);
576         return(to - from);
577 }
578
579 static int externfs_removepage(struct page *page, int gfpmask)
580 {
581         physmem_remove_mapping(page_address(page));
582         return(0);
583 }
584
585 static struct address_space_operations externfs_aops = {
586         .writepage      = externfs_writepage,
587         .readpage       = externfs_readpage,
588         .releasepage    = externfs_removepage,
589 /*      .set_page_dirty = __set_page_dirty_nobuffers, */
590         .prepare_write  = externfs_prepare_write,
591         .commit_write   = externfs_commit_write
592 };
593
594 static int init_inode(struct inode *inode, struct dentry *dentry)
595 {
596         char *name = NULL;
597         int type, err = -ENOMEM, rdev;
598         struct externfs_inode *ext = EXTERNFS_I(inode);
599         struct externfs_file_ops *ops = ext->ops;
600         struct externfs_data *ed = inode->i_sb->s_fs_info;      
601
602         if(dentry){
603                 name = dentry_name(dentry, 0);
604                 if(name == NULL)
605                         goto out;
606                 type = (*ops->file_type)(name, &rdev, ed);
607         }
608         else type = OS_TYPE_DIR;
609
610         err = 0;
611         if(type == OS_TYPE_SYMLINK)
612                 inode->i_op = &page_symlink_inode_operations;
613         else if(type == OS_TYPE_DIR)
614                 inode->i_op = &externfs_dir_iops;
615         else inode->i_op = &externfs_iops;
616
617         if(type == OS_TYPE_DIR) inode->i_fop = &externfs_dir_fops;
618         else inode->i_fop = &externfs_file_fops;
619
620         if(type == OS_TYPE_SYMLINK) 
621                 inode->i_mapping->a_ops = &externfs_link_aops;
622         else inode->i_mapping->a_ops = &externfs_aops;
623
624         switch (type) {
625         case OS_TYPE_CHARDEV:
626                 init_special_inode(inode, S_IFCHR, rdev);
627                 break;
628         case OS_TYPE_BLOCKDEV:
629                 init_special_inode(inode, S_IFBLK, rdev);
630                 break;
631         case OS_TYPE_FIFO:
632                 init_special_inode(inode, S_IFIFO, 0);
633                 break;
634         case OS_TYPE_SOCK:
635                 init_special_inode(inode, S_IFSOCK, 0);
636                 break;
637         case OS_TYPE_SYMLINK:
638                 inode->i_mode = S_IFLNK | S_IRWXUGO;
639         }
640
641         err = (*ops->open_file)(ext, name, current->fsuid, current->fsgid, 
642                                 inode, ed);
643         if((err != -EISDIR) && (err != -ENOENT) && (err != -ENXIO))
644                 goto out_put;
645
646         err = 0;
647
648  out_free:
649         kfree(name);
650  out:
651         return(err);
652
653  out_put:
654         iput(inode);
655         goto out_free;
656 }
657
658 int externfs_create(struct inode *dir, struct dentry *dentry, int mode, 
659                   struct nameidata *nd)
660 {
661         struct externfs_inode *ext = EXTERNFS_I(dir);
662         struct externfs_file_ops *ops = ext->ops;
663         struct inode *inode;
664         struct externfs_data *ed = dir->i_sb->s_fs_info;
665         char *name;
666         int err = -ENOMEM;
667
668         inode = iget(dir->i_sb, 0);
669         if(inode == NULL) 
670                 goto out;
671
672         err = init_inode(inode, dentry);
673         if(err) 
674                 goto out_put;
675         
676         err = -ENOMEM;
677         name = dentry_name(dentry, 0);
678         if(name == NULL)
679                 goto out_put;
680
681         err = (*ops->create_file)(ext, name, mode, current->fsuid, 
682                                   current->fsuid, inode, ed);
683         if(err)
684                 goto out_free;
685
686         err = read_name(inode, name);
687         if(err)
688                 goto out_rm;
689
690         inode->i_nlink++;
691         d_instantiate(dentry, inode);
692         kfree(name);
693  out:
694         return(err);
695
696  out_rm:
697         (*ops->unlink_file)(name, ed);
698  out_free:
699         kfree(name);
700  out_put:
701         inode->i_nlink = 0;
702         iput(inode);
703         goto out;
704 }
705  
706 struct dentry *externfs_lookup(struct inode *ino, struct dentry *dentry, 
707                                struct nameidata *nd)
708 {
709         struct inode *inode;
710         char *name;
711         int err = -ENOMEM;
712
713         inode = iget(ino->i_sb, 0);
714         if(inode == NULL) 
715                 goto out;
716
717         err = init_inode(inode, dentry);
718         if(err) 
719                 goto out_put;
720         
721         err = -ENOMEM;
722         name = dentry_name(dentry, 0);
723         if(name == NULL)
724                 goto out_put;
725
726         err = read_name(inode, name);
727         kfree(name);
728         if(err){
729                 if(err != -ENOENT)
730                         goto out_put;
731
732                 inode->i_nlink = 0;
733                 iput(inode);
734                 inode = NULL;
735         }
736         d_add(dentry, inode);
737         dentry->d_op = &externfs_dentry_ops;
738         return(NULL);
739
740  out_put:
741         inode->i_nlink = 0;
742         iput(inode);
743  out:
744         return(ERR_PTR(err));
745 }
746
747 static char *inode_dentry_name(struct inode *ino, struct dentry *dentry)
748 {
749         char *file;
750         int len;
751
752         file = inode_name(ino, dentry->d_name.len + 1);
753         if(file == NULL) return(NULL);
754         strcat(file, "/");
755         len = strlen(file);
756         strncat(file, dentry->d_name.name, dentry->d_name.len);
757         file[len + dentry->d_name.len] = '\0';
758         return(file);
759 }
760
761 int externfs_link(struct dentry *to, struct inode *ino, struct dentry *from)
762 {
763         struct externfs_file_ops *ops = EXTERNFS_I(ino)->ops;
764         struct externfs_data *ed = ino->i_sb->s_fs_info;
765         char *from_name, *to_name;
766         int err = -ENOMEM;
767
768         from_name = inode_dentry_name(ino, from); 
769         if(from_name == NULL) 
770                 goto out;
771
772         to_name = dentry_name(to, 0);
773         if(to_name == NULL)
774                 goto out_free_from;
775
776         err = (*ops->link_file)(to_name, from_name, current->fsuid, 
777                                 current->fsgid, ed);
778         if(err)
779                 goto out_free_to;
780
781         d_instantiate(from, to->d_inode);
782         to->d_inode->i_nlink++;
783         atomic_inc(&to->d_inode->i_count);
784
785  out_free_to:
786         kfree(to_name);
787  out_free_from:
788         kfree(from_name);
789  out:
790         return(err);
791 }
792
793 int externfs_unlink(struct inode *ino, struct dentry *dentry)
794 {
795         struct inode *inode;
796         struct externfs_file_ops *ops = EXTERNFS_I(ino)->ops;
797         struct externfs_data *ed = ino->i_sb->s_fs_info;
798         char *file;
799         int err;
800
801         file = inode_dentry_name(ino, dentry);
802         if(file == NULL) 
803                 return(-ENOMEM);
804
805         inode = dentry->d_inode;
806         if((inode->i_nlink == 1) && (ops->invisible != NULL))
807                 (*ops->invisible)(EXTERNFS_I(inode));
808
809         err = (*ops->unlink_file)(file, ed);
810         kfree(file);
811
812         inode->i_nlink--;
813
814         return(err);
815 }
816
817 int externfs_symlink(struct inode *ino, struct dentry *dentry, const char *to)
818 {
819         struct externfs_file_ops *ops = EXTERNFS_I(ino)->ops;
820         struct inode *inode;
821         struct externfs_data *ed = ino->i_sb->s_fs_info;
822         char *file;
823         int err;
824
825         file = inode_dentry_name(ino, dentry);
826         if(file == NULL) 
827                 return(-ENOMEM);
828         err = (*ops->make_symlink)(file, to, current->fsuid, current->fsgid,
829                                    ed);
830         kfree(file);
831         if(err) 
832                 goto out;
833
834         err = -ENOMEM;
835         inode = iget(ino->i_sb, 0);
836         if(inode == NULL) 
837                 goto out;
838
839         err = init_inode(inode, dentry);
840         if(err) 
841                 goto out_put;
842         
843         d_instantiate(dentry, inode);
844         inode->i_nlink++;
845  out:
846         return(err);
847
848  out_put:
849         iput(inode);
850         goto out;
851 }
852
853 int externfs_make_dir(struct inode *ino, struct dentry *dentry, int mode)
854 {
855         struct externfs_file_ops *ops = EXTERNFS_I(ino)->ops;
856         struct inode *inode;
857         struct externfs_data *ed = ino->i_sb->s_fs_info;
858         char *file;
859         int err = -ENOMEM;
860
861         file = inode_dentry_name(ino, dentry);
862         if(file == NULL) 
863                 goto out;
864         err = (*ops->make_dir)(file, mode, current->fsuid, current->fsgid, ed);
865
866         err = -ENOMEM;
867         inode = iget(ino->i_sb, 0);
868         if(inode == NULL) 
869                 goto out_free;
870
871         err = init_inode(inode, dentry);
872         if(err) 
873                 goto out_put;
874         
875         err = read_name(inode, file);
876         if(err)
877                 goto out_put;
878
879         kfree(file);
880         d_instantiate(dentry, inode);
881         inode->i_nlink = 2;
882         inode->i_mode = S_IFDIR | mode;
883
884         ino->i_nlink++;
885  out:
886         return(err);
887  out_put:
888         inode->i_nlink = 0;
889         iput(inode);
890  out_free:
891         kfree(file);
892         goto out;       
893 }
894
895 int externfs_remove_dir(struct inode *ino, struct dentry *dentry)
896 {
897         struct externfs_file_ops *ops = EXTERNFS_I(ino)->ops;
898         struct externfs_data *ed = ino->i_sb->s_fs_info;
899         char *file;
900         int err;
901
902         file = inode_dentry_name(ino, dentry);
903         if(file == NULL) 
904                 return(-ENOMEM);
905         err = (*ops->remove_dir)(file, current->fsuid, current->fsgid, ed);
906         kfree(file);
907
908         dentry->d_inode->i_nlink = 0;
909         ino->i_nlink--;
910         return(err);
911 }
912
913 int externfs_make_node(struct inode *dir, struct dentry *dentry, int mode, 
914                      dev_t dev)
915 {
916         struct externfs_file_ops *ops = EXTERNFS_I(dir)->ops;
917         struct externfs_data *ed = dir->i_sb->s_fs_info;
918         struct inode *inode;
919         char *name;
920         int err = -ENOMEM;
921  
922         inode = iget(dir->i_sb, 0);
923         if(inode == NULL) 
924                 goto out;
925
926         err = init_inode(inode, dentry);
927         if(err) 
928                 goto out_put;
929
930         err = -ENOMEM;
931         name = dentry_name(dentry, 0);
932         if(name == NULL)
933                 goto out_put;
934
935         init_special_inode(inode, mode, dev);
936         err = (*ops->make_node)(name, mode & S_IRWXUGO, current->fsuid, 
937                                 current->fsgid, mode & S_IFMT, MAJOR(dev), 
938                                 MINOR(dev), ed);
939         if(err)
940                 goto out_free;
941         
942         err = read_name(inode, name);
943         if(err)
944                 goto out_rm;
945
946         inode->i_nlink++;
947         d_instantiate(dentry, inode);
948         kfree(name);
949  out:
950         return(err);
951
952  out_rm:
953         (*ops->unlink_file)(name, ed);
954  out_free:
955         kfree(name);
956  out_put:
957         inode->i_nlink = 0;
958         iput(inode);
959         goto out;
960 }
961
962 int externfs_rename(struct inode *from_ino, struct dentry *from,
963                   struct inode *to_ino, struct dentry *to)
964 {
965         struct externfs_file_ops *ops = EXTERNFS_I(from_ino)->ops;
966         struct externfs_data *ed = from_ino->i_sb->s_fs_info;
967         char *from_name, *to_name;
968         int err;
969
970         from_name = inode_dentry_name(from_ino, from);
971         if(from_name == NULL)
972                 return(-ENOMEM);
973         to_name = inode_dentry_name(to_ino, to);
974         if(to_name == NULL){
975                 kfree(from_name);
976                 return(-ENOMEM);
977         }
978         err = (*ops->rename_file)(from_name, to_name, ed);
979         kfree(from_name);
980         kfree(to_name);
981
982         from_ino->i_nlink--;
983         to_ino->i_nlink++;
984         return(err);
985 }
986
987 void externfs_truncate(struct inode *ino)
988 {
989         struct externfs_file_ops *ops = EXTERNFS_I(ino)->ops;
990         struct externfs_data *ed = ino->i_sb->s_fs_info;
991
992         (*ops->truncate_file)(EXTERNFS_I(ino), ino->i_size, ed);
993 }
994
995 int externfs_permission(struct inode *ino, int desired, struct nameidata *nd)
996 {
997         struct externfs_file_ops *ops = EXTERNFS_I(ino)->ops;
998         struct externfs_data *ed = ino->i_sb->s_fs_info;
999         char *name;
1000         int r = 0, w = 0, x = 0, err;
1001
1002         if(ops->access_file == NULL)
1003                 return(vfs_permission(ino, desired));
1004
1005         if(desired & MAY_READ) r = 1;
1006         if(desired & MAY_WRITE) w = 1;
1007         if(desired & MAY_EXEC) x = 1;
1008         name = inode_name(ino, 0);
1009         if(name == NULL) 
1010                 return(-ENOMEM);
1011
1012         err = (*ops->access_file)(name, r, w, x, current->fsuid,
1013                                   current->fsgid, ed);
1014         kfree(name);
1015
1016         if(!err) 
1017                 err = vfs_permission(ino, desired);
1018         return(err);
1019 }
1020
1021 int externfs_setattr(struct dentry *dentry, struct iattr *attr)
1022 {
1023         struct externfs_file_ops *ops = EXTERNFS_I(dentry->d_inode)->ops;
1024         struct externfs_data *ed = dentry->d_inode->i_sb->s_fs_info;
1025         struct externfs_iattr attrs;
1026         char *name;
1027         int err;
1028         
1029         attrs.ia_valid = 0;
1030         if(attr->ia_valid & ATTR_MODE){
1031                 attrs.ia_valid |= EXTERNFS_ATTR_MODE;
1032                 attrs.ia_mode = attr->ia_mode;
1033         }
1034         if(attr->ia_valid & ATTR_UID){
1035                 attrs.ia_valid |= EXTERNFS_ATTR_UID;
1036                 attrs.ia_uid = attr->ia_uid;
1037         }
1038         if(attr->ia_valid & ATTR_GID){
1039                 attrs.ia_valid |= EXTERNFS_ATTR_GID;
1040                 attrs.ia_gid = attr->ia_gid;
1041         }
1042         if(attr->ia_valid & ATTR_SIZE){
1043                 attrs.ia_valid |= EXTERNFS_ATTR_SIZE;
1044                 attrs.ia_size = attr->ia_size;
1045         }
1046         if(attr->ia_valid & ATTR_ATIME){
1047                 attrs.ia_valid |= EXTERNFS_ATTR_ATIME;
1048                 attrs.ia_atime = attr->ia_atime.tv_sec;
1049         }
1050         if(attr->ia_valid & ATTR_MTIME){
1051                 attrs.ia_valid |= EXTERNFS_ATTR_MTIME;
1052                 attrs.ia_mtime = attr->ia_mtime.tv_sec;
1053         }
1054         if(attr->ia_valid & ATTR_CTIME){
1055                 attrs.ia_valid |= EXTERNFS_ATTR_CTIME;
1056                 attrs.ia_ctime = attr->ia_ctime.tv_sec;
1057         }
1058         if(attr->ia_valid & ATTR_ATIME_SET){
1059                 attrs.ia_valid |= EXTERNFS_ATTR_ATIME_SET;
1060                 attrs.ia_atime = attr->ia_atime.tv_sec;
1061         }
1062         if(attr->ia_valid & ATTR_MTIME_SET){
1063                 attrs.ia_valid |= EXTERNFS_ATTR_MTIME_SET;
1064         }
1065         name = dentry_name(dentry, 0);
1066         if(name == NULL) 
1067                 return(-ENOMEM);
1068         err = (*ops->set_attr)(name, &attrs, ed);
1069         kfree(name);
1070         if(err)
1071                 return(err);
1072
1073         return(inode_setattr(dentry->d_inode, attr));
1074 }
1075
1076 int externfs_getattr(struct vfsmount *mnt, struct dentry *dentry, 
1077                      struct kstat *stat)
1078 {
1079         generic_fillattr(dentry->d_inode, stat);
1080         return(0);
1081 }
1082
1083 static struct inode_operations externfs_iops = {
1084         .create         = externfs_create,
1085         .link           = externfs_link,
1086         .unlink         = externfs_unlink,
1087         .symlink        = externfs_symlink,
1088         .mkdir          = externfs_make_dir,
1089         .rmdir          = externfs_remove_dir,
1090         .mknod          = externfs_make_node,
1091         .rename         = externfs_rename,
1092         .truncate       = externfs_truncate,
1093         .permission     = externfs_permission,
1094         .setattr        = externfs_setattr,
1095         .getattr        = externfs_getattr,
1096 };
1097
1098 static struct inode_operations externfs_dir_iops = {
1099         .create         = externfs_create,
1100         .lookup         = externfs_lookup,
1101         .link           = externfs_link,
1102         .unlink         = externfs_unlink,
1103         .symlink        = externfs_symlink,
1104         .mkdir          = externfs_make_dir,
1105         .rmdir          = externfs_remove_dir,
1106         .mknod          = externfs_make_node,
1107         .rename         = externfs_rename,
1108         .truncate       = externfs_truncate,
1109         .permission     = externfs_permission,
1110         .setattr        = externfs_setattr,
1111         .getattr        = externfs_getattr,
1112 };
1113
1114 int externfs_link_readpage(struct file *file, struct page *page)
1115 {
1116         struct inode *ino = page->mapping->host;
1117         struct externfs_file_ops *ops = EXTERNFS_I(ino)->ops;
1118         struct externfs_data *ed = ino->i_sb->s_fs_info;
1119         char *buffer, *name;
1120         long long start;
1121         int err;
1122
1123         start = page->index << PAGE_CACHE_SHIFT;
1124         buffer = kmap(page);
1125         name = inode_name(ino, 0);
1126         if(name == NULL) 
1127                 return(-ENOMEM);
1128
1129         err = (*ops->read_link)(name, current->fsuid, current->fsgid, buffer, 
1130                                 PAGE_CACHE_SIZE, ed);
1131
1132         kfree(name);
1133         if(err == PAGE_CACHE_SIZE)
1134                 err = -E2BIG;
1135         else if(err > 0){
1136                 flush_dcache_page(page);
1137                 SetPageUptodate(page);
1138                 if (PageError(page)) ClearPageError(page);
1139                 err = 0;
1140         }
1141         kunmap(page);
1142         unlock_page(page);
1143         return(err);
1144 }
1145
1146 static int externfs_flushpage(struct page *page, unsigned long offset)
1147 {
1148         return(externfs_writepage(page, NULL));
1149 }
1150
1151 struct externfs_data *inode_externfs_info(struct inode *inode)
1152 {
1153         return(inode->i_sb->s_fs_info);
1154 }
1155
1156 static struct address_space_operations externfs_link_aops = {
1157         .readpage       = externfs_link_readpage,
1158         .releasepage    = externfs_removepage,
1159         .invalidatepage = externfs_flushpage,
1160 };
1161
1162 DECLARE_MUTEX(externfs_sem);
1163 struct list_head externfses = LIST_HEAD_INIT(externfses);
1164
1165 static struct externfs *find_externfs(struct file_system_type *type)
1166 {
1167         struct list_head *ele;
1168         struct externfs *fs;
1169
1170         down(&externfs_sem);
1171         list_for_each(ele, &externfses){
1172                 fs = list_entry(ele, struct externfs, list);
1173                 if(&fs->type == type)
1174                         goto out;
1175         }
1176         fs = NULL;
1177  out:
1178         up(&externfs_sem);
1179         return(fs);
1180 }
1181
1182 #define DEFAULT_ROOT "/"
1183
1184 char *host_root_filename(char *mount_arg)
1185 {
1186         char *root = DEFAULT_ROOT;
1187
1188         if((mount_arg != NULL) && (*mount_arg != '\0'))
1189                 root = mount_arg;
1190
1191         return(uml_strdup(root));
1192 }
1193
1194 static int externfs_fill_sb(struct super_block *sb, void *data, int silent)
1195 {
1196         struct externfs *fs;
1197         struct inode *root_inode;
1198         struct externfs_data *sb_data;
1199         int err = -EINVAL;
1200
1201         sb->s_blocksize = 1024;
1202         sb->s_blocksize_bits = 10;
1203         sb->s_magic = EXTERNFS_SUPER_MAGIC;
1204         sb->s_op = &externfs_sbops;
1205
1206         fs = find_externfs(sb->s_type);
1207         if(fs == NULL){
1208                 printk("Couldn't find externfs for filesystem '%s'\n",
1209                        sb->s_type->name);
1210                 goto out;
1211         }
1212
1213         sb_data = (*fs->mount_ops->mount)(data);
1214         if(IS_ERR(sb_data)){
1215                 err = PTR_ERR(sb_data);
1216                 goto out;
1217         }
1218                 
1219         sb->s_fs_info = sb_data;
1220         sb_data->mount_ops = fs->mount_ops;
1221
1222         root_inode = iget(sb, 0);
1223         if(root_inode == NULL)
1224                 goto out;
1225
1226         err = init_inode(root_inode, NULL);
1227         if(err)
1228                 goto out_put;
1229
1230         err = -ENOMEM;
1231         sb->s_root = d_alloc_root(root_inode);
1232         if(sb->s_root == NULL)
1233                 goto out_put;
1234
1235         err = read_inode(root_inode);
1236         if(err)
1237                 goto out_put;
1238
1239  out:
1240         return(err);
1241
1242  out_put:
1243         iput(root_inode);
1244         goto out;
1245 }       
1246
1247 struct super_block *externfs_read_super(struct file_system_type *type, 
1248                                         int flags, const char *dev_name, 
1249                                         void *data)
1250 {
1251         return(get_sb_nodev(type, flags, data, externfs_fill_sb));
1252 }
1253
1254 void init_externfs(struct externfs_data *ed, struct externfs_file_ops *ops)
1255 {
1256         ed->file_ops = ops;
1257 }
1258
1259 int register_externfs(char *name, struct externfs_mount_ops *mount_ops)
1260 {
1261         struct externfs *new;
1262         int err = -ENOMEM;
1263
1264         new = kmalloc(sizeof(*new), GFP_KERNEL);
1265         if(new == NULL)
1266                 goto out;
1267
1268         memset(new, 0, sizeof(*new));
1269         *new = ((struct externfs) { .list       = LIST_HEAD_INIT(new->list),
1270                                     .mount_ops  = mount_ops,
1271                                     .type = { .name     = name,
1272                                               .get_sb   = externfs_read_super,
1273                                               .kill_sb  = kill_anon_super,
1274                                               .fs_flags = 0,
1275                                               .owner    = THIS_MODULE } });
1276         list_add(&new->list, &externfses);
1277
1278         err = register_filesystem(&new->type);
1279         if(err)
1280                 goto out_del;
1281         return(0);
1282
1283  out_del:
1284         list_del(&new->list);
1285         kfree(new);
1286  out:
1287         return(err);
1288 }
1289
1290 void unregister_externfs(char *name)
1291 {
1292         struct list_head *ele;
1293         struct externfs *fs;
1294
1295         down(&externfs_sem);
1296         list_for_each(ele, &externfses){
1297                 fs = list_entry(ele, struct externfs, list);
1298                 if(!strcmp(fs->type.name, name)){
1299                         list_del(ele);
1300                         up(&externfs_sem);
1301                         return;
1302                 }
1303         }
1304         up(&externfs_sem);
1305         printk("Unregister_externfs - filesystem '%s' not found\n", name);
1306 }
1307
1308 /*
1309  * Overrides for Emacs so that we follow Linus's tabbing style.
1310  * Emacs will notice this stuff at the end of the file and automatically
1311  * adjust the settings for this buffer only.  This must remain at the end
1312  * of the file.
1313  * ---------------------------------------------------------------------------
1314  * Local variables:
1315  * c-file-style: "linux"
1316  * End:
1317  */