updated UML.
authorGerd Hoffmann <kraxel@suse.de>
Mon, 27 Oct 2003 14:06:57 +0000 (14:06 +0000)
committerGerd Hoffmann <kraxel@suse.de>
Mon, 27 Oct 2003 14:06:57 +0000 (14:06 +0000)
suse-commit: 1668b9e7dd0160bd18b748e5a350899fd2200363

arch/um/Kconfig
arch/um/defconfig
arch/um/kernel/irq.c
fs/Makefile
fs/hostfs/Makefile [new file with mode: 0644]
fs/hostfs/hostfs.h [new file with mode: 0644]
fs/hostfs/hostfs_kern.c [new file with mode: 0644]
fs/hostfs/hostfs_user.c [new file with mode: 0644]
fs/hppfs/Makefile [new file with mode: 0644]
fs/hppfs/hppfs_kern.c [new file with mode: 0644]
mm/memory.c

index 6bc27da..d77b9c8 100644 (file)
@@ -99,6 +99,19 @@ config HOSTFS
         If you'd like to be able to work with files stored on the host, 
         say Y or M here; otherwise say N.
 
+config HPPFS
+       tristate "HoneyPot ProcFS"
+       help
+       hppfs (HoneyPot ProcFS) is a filesystem which allows UML /proc 
+       entries to be overridden, removed, or fabricated from the host.
+       Its purpose is to allow a UML to appear to be a physical machine
+       by removing or changing anything in /proc which gives away the
+       identity of a UML.
+
+       See http://user-mode-linux.sf.net/hppfs.html for more information.
+
+       You only need this if you are setting up a UML honeypot.  Otherwise,
+       it is safe to say 'N' here.
 
 config MCONSOLE
        bool "Management console"
index 1e5479b..0a7650c 100644 (file)
@@ -144,7 +144,9 @@ CONFIG_IPV6_SCTP__=y
 # CONFIG_IP_SCTP is not set
 # CONFIG_ATM is not set
 # CONFIG_VLAN_8021Q is not set
-# CONFIG_LLC is not set
+# CONFIG_LLC2 is not set
+# CONFIG_IPX is not set
+# CONFIG_ATALK is not set
 # CONFIG_X25 is not set
 # CONFIG_LAPB is not set
 # CONFIG_NET_DIVERT is not set
@@ -198,7 +200,7 @@ CONFIG_SLIP=y
 # CONFIG_NET_RADIO is not set
 
 #
-# Token Ring devices (depends on LLC=y)
+# Token Ring devices
 #
 # CONFIG_SHAPER is not set
 
@@ -208,6 +210,21 @@ CONFIG_SLIP=y
 # CONFIG_WAN is not set
 
 #
+# Amateur Radio support
+#
+# CONFIG_HAMRADIO is not set
+
+#
+# IrDA (infrared) support
+#
+# CONFIG_IRDA is not set
+
+#
+# Bluetooth support
+#
+# CONFIG_BT is not set
+
+#
 # File systems
 #
 CONFIG_EXT2_FS=y
@@ -248,12 +265,14 @@ CONFIG_VFAT_FS=y
 # Pseudo filesystems
 #
 CONFIG_PROC_FS=y
+CONFIG_PROC_KCORE=y
 CONFIG_DEVFS_FS=y
 CONFIG_DEVFS_MOUNT=y
 # CONFIG_DEVFS_DEBUG is not set
 CONFIG_DEVPTS_FS=y
 # CONFIG_DEVPTS_FS_XATTR is not set
 # CONFIG_TMPFS is not set
+# CONFIG_HUGETLB_PAGE is not set
 CONFIG_RAMFS=y
 
 #
index 358e250..5af2dd0 100644 (file)
@@ -243,8 +243,7 @@ void enable_irq(unsigned int irq)
        spin_lock_irqsave(&desc->lock, flags);
        switch (desc->depth) {
        case 1: {
-               unsigned int status = 
-                       desc->status & ~(IRQ_DISABLED | IRQ_INPROGRESS);
+               unsigned int status = desc->status & IRQ_DISABLED;
                desc->status = status;
                if ((status & (IRQ_PENDING | IRQ_REPLAY)) == IRQ_PENDING) {
                        desc->status = status | IRQ_REPLAY;
index ffd13f9..4ada828 100644 (file)
@@ -91,3 +91,5 @@ obj-$(CONFIG_JFS_FS)          += jfs/
 obj-$(CONFIG_XFS_FS)           += xfs/
 obj-$(CONFIG_AFS_FS)           += afs/
 obj-$(CONFIG_BEFS_FS)          += befs/
+obj-$(CONFIG_HOSTFS)           += hostfs/
+obj-$(CONFIG_HPPFS)            += hppfs/
diff --git a/fs/hostfs/Makefile b/fs/hostfs/Makefile
new file mode 100644 (file)
index 0000000..17ba718
--- /dev/null
@@ -0,0 +1,36 @@
+# 
+# Copyright (C) 2000 Jeff Dike (jdike@karaya.com)
+# Licensed under the GPL
+#
+
+# struct stat64 changed the inode field name between 2.2 and 2.4 from st_ino
+# to __st_ino.  It stayed in the same place, so as long as the correct name
+# is used, hostfs compiled on 2.2 should work on 2.4 and vice versa.
+
+STAT64_INO_FIELD := $(shell grep -q __st_ino /usr/include/bits/stat.h && \
+                               echo __)st_ino
+
+hostfs-objs := hostfs_kern.o hostfs_user.o
+
+obj-y = 
+obj-$(CONFIG_HOSTFS) += hostfs.o
+
+SINGLE_OBJS = $(foreach f,$(patsubst %.o,%,$(obj-y) $(obj-m)),$($(f)-objs))
+
+USER_OBJS := $(filter %_user.o,$(obj-y) $(obj-m) $(SINGLE_OBJS))
+USER_OBJS := $(foreach file,$(USER_OBJS),$(obj)/$(file))
+
+USER_CFLAGS += -DSTAT64_INO_FIELD=$(STAT64_INO_FIELD)
+
+$(USER_OBJS) : %.o: %.c
+       $(CC) $(CFLAGS_$(notdir $@)) $(USER_CFLAGS) -c -o $@ $<
+
+clean:
+
+modules:
+
+fastdep:
+
+dep:
+
+archmrproper: clean
diff --git a/fs/hostfs/hostfs.h b/fs/hostfs/hostfs.h
new file mode 100644 (file)
index 0000000..d1f6c33
--- /dev/null
@@ -0,0 +1,79 @@
+#ifndef __UM_FS_HOSTFS
+#define __UM_FS_HOSTFS
+
+#include "os.h"
+
+/* These are exactly the same definitions as in fs.h, but the names are 
+ * changed so that this file can be included in both kernel and user files.
+ */
+
+#define HOSTFS_ATTR_MODE       1
+#define HOSTFS_ATTR_UID        2
+#define HOSTFS_ATTR_GID        4
+#define HOSTFS_ATTR_SIZE       8
+#define HOSTFS_ATTR_ATIME      16
+#define HOSTFS_ATTR_MTIME      32
+#define HOSTFS_ATTR_CTIME      64
+#define HOSTFS_ATTR_ATIME_SET  128
+#define HOSTFS_ATTR_MTIME_SET  256
+#define HOSTFS_ATTR_FORCE      512     /* Not a change, but a change it */
+#define HOSTFS_ATTR_ATTR_FLAG  1024
+
+struct hostfs_iattr {
+       unsigned int    ia_valid;
+       mode_t          ia_mode;
+       uid_t           ia_uid;
+       gid_t           ia_gid;
+       loff_t          ia_size;
+       struct timespec ia_atime;
+       struct timespec ia_mtime;
+       struct timespec ia_ctime;
+       unsigned int    ia_attr_flags;
+};
+
+extern int stat_file(const char *path, unsigned long long *inode_out, 
+                    int *mode_out, int *nlink_out, int *uid_out, int *gid_out,
+                    unsigned long long *size_out, struct timespec *atime_out, 
+                    struct timespec *mtime_out, struct timespec *ctime_out, 
+                    int *blksize_out, unsigned long long *blocks_out);
+extern int access_file(char *path, int r, int w, int x);
+extern int open_file(char *path, int r, int w, int append);
+extern int file_type(const char *path, int *rdev);
+extern void *open_dir(char *path, int *err_out);
+extern char *read_dir(void *stream, unsigned long long *pos, 
+                     unsigned long long *ino_out, int *len_out);
+extern void close_file(void *stream);
+extern void close_dir(void *stream);
+extern int read_file(int fd, unsigned long long *offset, char *buf, int len);
+extern int write_file(int fd, unsigned long long *offset, const char *buf,
+                     int len);
+extern int lseek_file(int fd, long long offset, int whence);
+extern int file_create(char *name, int ur, int uw, int ux, int gr, 
+                      int gw, int gx, int or, int ow, int ox);
+extern int set_attr(const char *file, struct hostfs_iattr *attrs);
+extern int make_symlink(const char *from, const char *to);
+extern int unlink_file(const char *file);
+extern int do_mkdir(const char *file, int mode);
+extern int do_rmdir(const char *file);
+extern int do_mknod(const char *file, int mode, int dev);
+extern int link_file(const char *from, const char *to);
+extern int do_readlink(char *file, char *buf, int size);
+extern int rename_file(char *from, char *to);
+extern int do_statfs(char *root, long *bsize_out, long long *blocks_out, 
+                    long long *bfree_out, long long *bavail_out, 
+                    long long *files_out, long long *ffree_out, 
+                    void *fsid_out, int fsid_size, long *namelen_out, 
+                    long *spare_out);
+
+#endif
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff --git a/fs/hostfs/hostfs_kern.c b/fs/hostfs/hostfs_kern.c
new file mode 100644 (file)
index 0000000..ef5d5d1
--- /dev/null
@@ -0,0 +1,1008 @@
+/* 
+ * Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ *
+ * Ported the filesystem routines to 2.5.
+ * 2003-02-10 Petr Baudis <pasky@ucw.cz>
+ */
+
+#include <linux/stddef.h>
+#include <linux/fs.h>
+#include <linux/version.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/pagemap.h>
+#include <linux/blkdev.h>
+#include <linux/list.h>
+#include <linux/buffer_head.h>
+#include <linux/root_dev.h>
+#include <linux/statfs.h>
+#include <asm/uaccess.h>
+#include "hostfs.h"
+#include "kern_util.h"
+#include "kern.h"
+#include "user_util.h"
+#include "2_5compat.h"
+#include "init.h"
+
+struct hostfs_inode_info {
+       char *host_filename;
+       int fd;
+       int mode;
+       struct inode vfs_inode;
+};
+
+static inline struct hostfs_inode_info *HOSTFS_I(struct inode *inode)
+{
+       return(list_entry(inode, struct hostfs_inode_info, vfs_inode));
+}
+
+#define FILE_HOSTFS_I(file) HOSTFS_I((file)->f_dentry->d_inode)
+
+int hostfs_d_delete(struct dentry *dentry)
+{
+       return(1);
+}
+
+struct dentry_operations hostfs_dentry_ops = {
+       .d_delete               = hostfs_d_delete,
+};
+
+/* Changed in hostfs_args before the kernel starts running */
+static char *root_ino = "/";
+static int append = 0;
+
+#define HOSTFS_SUPER_MAGIC 0x00c0ffee
+
+static struct inode_operations hostfs_iops;
+static struct inode_operations hostfs_dir_iops;
+static struct address_space_operations hostfs_link_aops;
+
+static int __init hostfs_args(char *options, int *add)
+{
+       char *ptr;
+
+       ptr = strchr(options, ',');
+       if(ptr != NULL)
+               *ptr++ = '\0';
+       if(*options != '\0')
+               root_ino = options;
+
+       options = ptr;
+       while(options){
+               ptr = strchr(options, ',');
+               if(ptr != NULL)
+                       *ptr++ = '\0';
+               if(*options != '\0'){
+                       if(!strcmp(options, "append"))
+                               append = 1;
+                       else printf("hostfs_args - unsupported option - %s\n",
+                                   options);
+               }
+               options = ptr;
+       }
+       return(0);
+}
+
+__uml_setup("hostfs=", hostfs_args,
+"hostfs=<root dir>,<flags>,...\n"
+"    This is used to set hostfs parameters.  The root directory argument\n"
+"    is used to confine all hostfs mounts to within the specified directory\n"
+"    tree on the host.  If this isn't specified, then a user inside UML can\n"
+"    mount anything on the host that's accessible to the user that's running\n"
+"    it.\n"
+"    The only flag currently supported is 'append', which specifies that all\n"
+"    files opened by hostfs will be opened in append mode.\n\n"
+);
+
+static char *dentry_name(struct dentry *dentry, int extra)
+{
+       struct dentry *parent;
+       char *root, *name;
+       int len;
+
+       len = 0;
+       parent = dentry;
+       while(parent->d_parent != parent){
+               len += parent->d_name.len + 1;
+               parent = parent->d_parent;
+       }
+       
+       root = HOSTFS_I(parent->d_inode)->host_filename;
+       len += strlen(root);
+       name = kmalloc(len + extra + 1, GFP_KERNEL);
+       if(name == NULL) return(NULL);
+
+       name[len] = '\0';
+       parent = dentry;
+       while(parent->d_parent != parent){
+               len -= parent->d_name.len + 1;
+               name[len] = '/';
+               strncpy(&name[len + 1], parent->d_name.name, 
+                       parent->d_name.len);
+               parent = parent->d_parent;
+       }
+       strncpy(name, root, strlen(root));
+       return(name);
+}
+
+static char *inode_name(struct inode *ino, int extra)
+{
+       struct dentry *dentry;
+
+       dentry = list_entry(ino->i_dentry.next, struct dentry, d_alias);
+       return(dentry_name(dentry, extra));
+}
+
+static int read_name(struct inode *ino, char *name)
+{
+       /* The non-int inode fields are copied into ints by stat_file and
+        * then copied into the inode because passing the actual pointers
+        * in and having them treated as int * breaks on big-endian machines
+        */
+       int err;
+       int i_mode, i_nlink, i_blksize;
+       unsigned long long i_size;
+       unsigned long long i_ino;
+       unsigned long long i_blocks;
+
+       err = stat_file(name, &i_ino, &i_mode, &i_nlink, &ino->i_uid, 
+                       &ino->i_gid, &i_size, &ino->i_atime, &ino->i_mtime, 
+                       &ino->i_ctime, &i_blksize, &i_blocks);
+       if(err) 
+               return(err);
+
+       ino->i_ino = i_ino;
+       ino->i_mode = i_mode;
+       ino->i_nlink = i_nlink;
+       ino->i_size = i_size;
+       ino->i_blksize = i_blksize;
+       ino->i_blocks = i_blocks;
+       if((ino->i_sb->s_dev == ROOT_DEV) && (ino->i_uid == getuid()))
+               ino->i_uid = 0;
+       return(0);
+}
+
+static char *follow_link(char *link)
+{
+       int len, n;
+       char *name, *resolved, *end;
+
+       len = 64;
+       while(1){
+               n = -ENOMEM;
+               name = kmalloc(len, GFP_KERNEL);
+               if(name == NULL)
+                       goto out;
+
+               n = do_readlink(link, name, len);
+               if(n < len)
+                       break;
+               len *= 2;
+               kfree(name);
+       }
+       if(n < 0)
+               goto out_free;
+
+       if(*name == '/')
+               return(name);
+
+       end = strrchr(link, '/');
+       if(end == NULL)
+               return(name);
+
+       *(end + 1) = '\0';
+       len = strlen(link) + strlen(name) + 1;
+
+       resolved = kmalloc(len, GFP_KERNEL);
+       if(resolved == NULL){
+               n = -ENOMEM;
+               goto out_free;
+       }
+
+       sprintf(resolved, "%s%s", link, name);
+       kfree(name);
+       kfree(link);
+       return(resolved);
+
+ out_free:
+       kfree(name);
+ out:
+       return(ERR_PTR(n));
+}
+
+static int read_inode(struct inode *ino)
+{
+       char *name;
+       int err = 0;
+
+       /* Unfortunately, we are called from iget() when we don't have a dentry
+        * allocated yet.
+        */
+       if(list_empty(&ino->i_dentry))
+               goto out;
+       err = -ENOMEM;
+       name = inode_name(ino, 0);
+       if(name == NULL) 
+               goto out;
+
+       if(file_type(name, NULL) == OS_TYPE_SYMLINK){
+               name = follow_link(name);
+               if(IS_ERR(name)){
+                       err = PTR_ERR(name);
+                       goto out;
+               }
+       }
+       
+       err = read_name(ino, name);
+       kfree(name);
+ out:
+       return(err);
+}
+
+int hostfs_statfs(struct super_block *sb, struct kstatfs *sf)
+{
+       /* do_statfs uses struct statfs64 internally, but the linux kernel
+        * struct statfs still has 32-bit versions for most of these fields,
+        * so we convert them here
+        */
+       int err;
+       long long f_blocks;
+       long long f_bfree;
+       long long f_bavail;
+       long long f_files;
+       long long f_ffree;
+
+       err = do_statfs(HOSTFS_I(sb->s_root->d_inode)->host_filename,
+                       &sf->f_bsize, &f_blocks, &f_bfree, &f_bavail, &f_files,
+                       &f_ffree, &sf->f_fsid, sizeof(sf->f_fsid), 
+                       &sf->f_namelen, sf->f_spare);
+       if(err) return(err);
+       sf->f_blocks = f_blocks;
+       sf->f_bfree = f_bfree;
+       sf->f_bavail = f_bavail;
+       sf->f_files = f_files;
+       sf->f_ffree = f_ffree;
+       sf->f_type = HOSTFS_SUPER_MAGIC;
+       return(0);
+}
+
+static struct inode *hostfs_alloc_inode(struct super_block *sb)
+{
+       struct hostfs_inode_info *hi;
+
+       hi = kmalloc(sizeof(*hi), GFP_KERNEL);
+       if(hi == NULL) 
+               return(NULL);
+
+       *hi = ((struct hostfs_inode_info) { .host_filename      = NULL,
+                                           .fd                 = -1,
+                                           .mode               = 0 });
+       inode_init_once(&hi->vfs_inode);
+       return(&hi->vfs_inode);
+}
+
+static void hostfs_destroy_inode(struct inode *inode)
+{
+       if(HOSTFS_I(inode)->host_filename) 
+               kfree(HOSTFS_I(inode)->host_filename);
+
+       if(HOSTFS_I(inode)->fd != -1) 
+               close_file(&HOSTFS_I(inode)->fd);
+
+       kfree(HOSTFS_I(inode));
+}
+
+static void hostfs_read_inode(struct inode *inode)
+{
+       read_inode(inode);
+}
+
+static struct super_operations hostfs_sbops = { 
+       .alloc_inode    = hostfs_alloc_inode,
+       .destroy_inode  = hostfs_destroy_inode,
+       .read_inode     = hostfs_read_inode,
+       .statfs         = hostfs_statfs,
+};
+
+int hostfs_readdir(struct file *file, void *ent, filldir_t filldir)
+{
+       void *dir;
+       char *name;
+       unsigned long long next, ino;
+       int error, len;
+
+       name = dentry_name(file->f_dentry, 0);
+       if(name == NULL) return(-ENOMEM);
+       dir = open_dir(name, &error);
+       kfree(name);
+       if(dir == NULL) return(-error);
+       next = file->f_pos;
+       while((name = read_dir(dir, &next, &ino, &len)) != NULL){
+               error = (*filldir)(ent, name, len, file->f_pos, 
+                                  ino, DT_UNKNOWN);
+               if(error) break;
+               file->f_pos = next;
+       }
+       close_dir(dir);
+       return(0);
+}
+
+int hostfs_file_open(struct inode *ino, struct file *file)
+{
+       char *name;
+       int mode = 0, r = 0, w = 0, fd;
+
+       mode = file->f_mode & (FMODE_READ | FMODE_WRITE);
+       if((mode & HOSTFS_I(ino)->mode) == mode)
+               return(0);
+
+       /* The file may already have been opened, but with the wrong access,
+        * so this resets things and reopens the file with the new access.
+        */
+       if(HOSTFS_I(ino)->fd != -1){
+               close_file(&HOSTFS_I(ino)->fd);
+               HOSTFS_I(ino)->fd = -1;
+       }
+
+       HOSTFS_I(ino)->mode |= mode;
+       if(HOSTFS_I(ino)->mode & FMODE_READ) 
+               r = 1;
+       if(HOSTFS_I(ino)->mode & FMODE_WRITE) 
+               w = 1;
+       if(w) 
+               r = 1;
+
+       name = dentry_name(file->f_dentry, 0);
+       if(name == NULL) 
+               return(-ENOMEM);
+
+       fd = open_file(name, r, w, append);
+       kfree(name);
+       if(fd < 0) return(fd);
+       FILE_HOSTFS_I(file)->fd = fd;
+
+       return(0);
+}
+
+int hostfs_fsync(struct file *file, struct dentry *dentry, int datasync)
+{
+       return(0);
+}
+
+static struct file_operations hostfs_file_fops = {
+       .llseek         = generic_file_llseek,
+       .read           = generic_file_read,
+       .write          = generic_file_write,
+       .mmap           = generic_file_mmap,
+       .open           = hostfs_file_open,
+       .release        = NULL,
+       .fsync          = hostfs_fsync,
+};
+
+static struct file_operations hostfs_dir_fops = {
+       .readdir        = hostfs_readdir,
+       .read           = generic_read_dir,
+};
+
+int hostfs_writepage(struct page *page, struct writeback_control *wbc)
+{
+       struct address_space *mapping = page->mapping;
+       struct inode *inode = mapping->host;
+       char *buffer;
+       unsigned long long base;
+       int count = PAGE_CACHE_SIZE;
+       int end_index = inode->i_size >> PAGE_CACHE_SHIFT;
+       int err;
+
+       if (page->index >= end_index)
+               count = inode->i_size & (PAGE_CACHE_SIZE-1);
+
+       buffer = kmap(page);
+       base = ((unsigned long long) page->index) << PAGE_CACHE_SHIFT;
+
+       err = write_file(HOSTFS_I(inode)->fd, &base, buffer, count);
+       if(err != count){
+               ClearPageUptodate(page);
+               goto out;
+       }
+
+       if (base > inode->i_size)
+               inode->i_size = base;
+
+       if (PageError(page))
+               ClearPageError(page);   
+       err = 0;
+
+ out:  
+       kunmap(page);
+
+       unlock_page(page);
+       return err; 
+}
+
+int hostfs_readpage(struct file *file, struct page *page)
+{
+       char *buffer;
+       long long start;
+       int err = 0;
+
+       start = (long long) page->index << PAGE_CACHE_SHIFT;
+       buffer = kmap(page);
+       err = read_file(FILE_HOSTFS_I(file)->fd, &start, buffer,
+                       PAGE_CACHE_SIZE);
+       if(err < 0) goto out;
+
+       memset(&buffer[err], 0, PAGE_CACHE_SIZE - err);
+
+       flush_dcache_page(page);
+       SetPageUptodate(page);
+       if (PageError(page)) ClearPageError(page);
+       err = 0;
+ out:
+       kunmap(page);
+       unlock_page(page);
+       return(err);
+}
+
+int hostfs_prepare_write(struct file *file, struct page *page, 
+                        unsigned int from, unsigned int to)
+{
+       char *buffer;
+       long long start, tmp;
+       int err;
+
+       start = (long long) page->index << PAGE_CACHE_SHIFT;
+       buffer = kmap(page);
+       if(from != 0){
+               tmp = start;
+               err = read_file(FILE_HOSTFS_I(file)->fd, &tmp, buffer,
+                               from);
+               if(err < 0) goto out;
+       }
+       if(to != PAGE_CACHE_SIZE){
+               start += to;
+               err = read_file(FILE_HOSTFS_I(file)->fd, &start, buffer + to,
+                               PAGE_CACHE_SIZE - to);
+               if(err < 0) goto out;           
+       }
+       err = 0;
+ out:
+       kunmap(page);
+       return(err);
+}
+
+int hostfs_commit_write(struct file *file, struct page *page, unsigned from,
+                unsigned to)
+{
+       struct address_space *mapping = page->mapping;
+       struct inode *inode = mapping->host;
+       char *buffer;
+       long long start;
+       int err = 0;
+
+       start = (long long) (page->index << PAGE_CACHE_SHIFT) + from;
+       buffer = kmap(page);
+       err = write_file(FILE_HOSTFS_I(file)->fd, &start, buffer + from, 
+                        to - from);
+       if(err > 0) err = 0;
+       if(!err && (start > inode->i_size))
+               inode->i_size = start;
+
+       kunmap(page);
+       return(err);
+}
+
+static struct address_space_operations hostfs_aops = {
+       .writepage      = hostfs_writepage,
+       .readpage       = hostfs_readpage,
+/*     .set_page_dirty = __set_page_dirty_nobuffers, */
+       .prepare_write  = hostfs_prepare_write,
+       .commit_write   = hostfs_commit_write
+};
+
+static int init_inode(struct inode *inode, struct dentry *dentry)
+{
+       char *name;
+       int type, err = -ENOMEM, rdev;
+
+       if(dentry){
+               name = dentry_name(dentry, 0);
+               if(name == NULL)
+                       goto out;
+               type = file_type(name, &rdev);
+               kfree(name);
+       }
+       else type = OS_TYPE_DIR;
+
+       err = 0;
+       if(type == OS_TYPE_SYMLINK)
+               inode->i_op = &page_symlink_inode_operations;
+       else if(type == OS_TYPE_DIR)
+               inode->i_op = &hostfs_dir_iops;
+       else inode->i_op = &hostfs_iops;
+
+       if(type == OS_TYPE_DIR) inode->i_fop = &hostfs_dir_fops;
+       else inode->i_fop = &hostfs_file_fops;
+
+       if(type == OS_TYPE_SYMLINK) 
+               inode->i_mapping->a_ops = &hostfs_link_aops;
+       else inode->i_mapping->a_ops = &hostfs_aops;
+
+       switch (type) {
+       case OS_TYPE_CHARDEV:
+               init_special_inode(inode, S_IFCHR, rdev);
+               break;
+       case OS_TYPE_BLOCKDEV:
+               init_special_inode(inode, S_IFBLK, rdev);
+               break;
+       case OS_TYPE_FIFO:
+               init_special_inode(inode, S_IFIFO, 0);
+               break;
+       case OS_TYPE_SOCK:
+               init_special_inode(inode, S_IFSOCK, 0);
+               break;
+       }
+ out:
+       return(err);
+}
+
+int hostfs_create(struct inode *dir, struct dentry *dentry, int mode, 
+                 struct nameidata *nd)
+{
+       struct inode *inode;
+       char *name;
+       int error, fd;
+
+       error = -ENOMEM;
+       inode = iget(dir->i_sb, 0);
+       if(inode == NULL) goto out;
+
+       error = init_inode(inode, dentry);
+       if(error) 
+               goto out_put;
+       
+       error = -ENOMEM;
+       name = dentry_name(dentry, 0);
+       if(name == NULL)
+               goto out_put;
+
+       fd = file_create(name, 
+                        mode & S_IRUSR, mode & S_IWUSR, mode & S_IXUSR, 
+                        mode & S_IRGRP, mode & S_IWGRP, mode & S_IXGRP, 
+                        mode & S_IROTH, mode & S_IWOTH, mode & S_IXOTH);
+       if(fd < 0) 
+               error = fd;
+       else error = read_name(inode, name);
+
+       kfree(name);
+       if(error)
+               goto out_put;
+
+       HOSTFS_I(inode)->fd = fd;
+       HOSTFS_I(inode)->mode = FMODE_READ | FMODE_WRITE;
+       d_instantiate(dentry, inode);
+       return(0);
+
+ out_put:
+       iput(inode);
+ out:
+       return(error);
+}
+
+struct dentry *hostfs_lookup(struct inode *ino, struct dentry *dentry, 
+                            struct nameidata *nd)
+{
+       struct inode *inode;
+       char *name;
+       int err;
+
+       err = -ENOMEM;
+       inode = iget(ino->i_sb, 0);
+       if(inode == NULL) 
+               goto out;
+       err = init_inode(inode, dentry);
+       if(err) 
+               goto out_put;
+
+       err = -ENOMEM;
+       name = dentry_name(dentry, 0);
+       if(name == NULL)
+               goto out_put;
+
+       err = read_name(inode, name);
+       kfree(name);
+       if(err == -ENOENT){
+               iput(inode);
+               inode = NULL;
+       }
+       else if(err)
+               goto out_put;
+
+       d_add(dentry, inode);
+       dentry->d_op = &hostfs_dentry_ops;
+       return(NULL);
+
+ out_put:
+       iput(inode);
+ out:
+       return(ERR_PTR(err));
+}
+
+static char *inode_dentry_name(struct inode *ino, struct dentry *dentry)
+{
+        char *file;
+       int len;
+
+       file = inode_name(ino, dentry->d_name.len + 1);
+       if(file == NULL) return(NULL);
+        strcat(file, "/");
+       len = strlen(file);
+        strncat(file, dentry->d_name.name, dentry->d_name.len);
+       file[len + dentry->d_name.len] = '\0';
+        return(file);
+}
+
+int hostfs_link(struct dentry *to, struct inode *ino, struct dentry *from)
+{
+        char *from_name, *to_name;
+        int err;
+
+        if((from_name = inode_dentry_name(ino, from)) == NULL) 
+                return(-ENOMEM);
+        to_name = dentry_name(to, 0);
+       if(to_name == NULL){
+               kfree(from_name);
+               return(-ENOMEM);
+       }
+        err = link_file(to_name, from_name);
+        kfree(from_name);
+        kfree(to_name);
+        return(err);
+}
+
+int hostfs_unlink(struct inode *ino, struct dentry *dentry)
+{
+       char *file;
+       int err;
+
+       if((file = inode_dentry_name(ino, dentry)) == NULL) return(-ENOMEM);
+       if(append)
+               return(-EPERM);
+
+       err = unlink_file(file);
+       kfree(file);
+       return(err);
+}
+
+int hostfs_symlink(struct inode *ino, struct dentry *dentry, const char *to)
+{
+       char *file;
+       int err;
+
+       if((file = inode_dentry_name(ino, dentry)) == NULL) return(-ENOMEM);
+       err = make_symlink(file, to);
+       kfree(file);
+       return(err);
+}
+
+int hostfs_mkdir(struct inode *ino, struct dentry *dentry, int mode)
+{
+       char *file;
+       int err;
+
+       if((file = inode_dentry_name(ino, dentry)) == NULL) return(-ENOMEM);
+       err = do_mkdir(file, mode);
+       kfree(file);
+       return(err);
+}
+
+int hostfs_rmdir(struct inode *ino, struct dentry *dentry)
+{
+       char *file;
+       int err;
+
+       if((file = inode_dentry_name(ino, dentry)) == NULL) return(-ENOMEM);
+       err = do_rmdir(file);
+       kfree(file);
+       return(err);
+}
+
+int hostfs_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t dev)
+{
+       struct inode *inode;
+       char *name;
+       int err = -ENOMEM;
+       inode = iget(dir->i_sb, 0);
+       if(inode == NULL) 
+               goto out;
+
+       err = init_inode(inode, dentry);
+       if(err) 
+               goto out_put;
+
+       err = -ENOMEM;
+       name = dentry_name(dentry, 0);
+       if(name == NULL)
+               goto out_put;
+
+       init_special_inode(inode, mode, dev);
+       err = do_mknod(name, mode, dev);
+       if(err)
+               goto out_free;
+
+       err = read_name(inode, name);
+       kfree(name);
+       if(err)
+               goto out_put;
+
+       d_instantiate(dentry, inode);
+       return(0);
+
+ out_free:
+       kfree(name);
+ out_put:
+       iput(inode);
+ out:
+       return(err);
+}
+
+int hostfs_rename(struct inode *from_ino, struct dentry *from,
+                 struct inode *to_ino, struct dentry *to)
+{
+       char *from_name, *to_name;
+       int err;
+
+       if((from_name = inode_dentry_name(from_ino, from)) == NULL)
+               return(-ENOMEM);
+       if((to_name = inode_dentry_name(to_ino, to)) == NULL){
+               kfree(from_name);
+               return(-ENOMEM);
+       }
+       err = rename_file(from_name, to_name);
+       kfree(from_name);
+       kfree(to_name);
+       return(err);
+}
+
+void hostfs_truncate(struct inode *ino)
+{
+       not_implemented();
+}
+
+int hostfs_permission(struct inode *ino, int desired, struct nameidata *nd)
+{
+       char *name;
+       int r = 0, w = 0, x = 0, err;
+
+       if(desired & MAY_READ) r = 1;
+       if(desired & MAY_WRITE) w = 1;
+       if(desired & MAY_EXEC) x = 1;
+       name = inode_name(ino, 0);
+       if(name == NULL) return(-ENOMEM);
+       err = access_file(name, r, w, x);
+       kfree(name);
+       if(!err) err = vfs_permission(ino, desired);
+       return(err);
+}
+
+int hostfs_setattr(struct dentry *dentry, struct iattr *attr)
+{
+       struct hostfs_iattr attrs;
+       char *name;
+       int err;
+       
+       if(append) 
+               attr->ia_valid &= ~ATTR_SIZE;
+
+       attrs.ia_valid = 0;
+       if(attr->ia_valid & ATTR_MODE){
+               attrs.ia_valid |= HOSTFS_ATTR_MODE;
+               attrs.ia_mode = attr->ia_mode;
+       }
+       if(attr->ia_valid & ATTR_UID){
+               if((dentry->d_inode->i_sb->s_dev == ROOT_DEV) && 
+                  (attr->ia_uid == 0))
+                       attr->ia_uid = getuid();
+               attrs.ia_valid |= HOSTFS_ATTR_UID;
+               attrs.ia_uid = attr->ia_uid;
+       }
+       if(attr->ia_valid & ATTR_GID){
+               if((dentry->d_inode->i_sb->s_dev == ROOT_DEV) && 
+                  (attr->ia_gid == 0))
+                       attr->ia_gid = getuid();
+               attrs.ia_valid |= HOSTFS_ATTR_GID;
+               attrs.ia_gid = attr->ia_gid;
+       }
+       if(attr->ia_valid & ATTR_SIZE){
+               attrs.ia_valid |= HOSTFS_ATTR_SIZE;
+               attrs.ia_size = attr->ia_size;
+       }
+       if(attr->ia_valid & ATTR_ATIME){
+               attrs.ia_valid |= HOSTFS_ATTR_ATIME;
+               attrs.ia_atime = attr->ia_atime;
+       }
+       if(attr->ia_valid & ATTR_MTIME){
+               attrs.ia_valid |= HOSTFS_ATTR_MTIME;
+               attrs.ia_mtime = attr->ia_mtime;
+       }
+       if(attr->ia_valid & ATTR_CTIME){
+               attrs.ia_valid |= HOSTFS_ATTR_CTIME;
+               attrs.ia_ctime = attr->ia_ctime;
+       }
+       if(attr->ia_valid & ATTR_ATIME_SET){
+               attrs.ia_valid |= HOSTFS_ATTR_ATIME_SET;
+       }
+       if(attr->ia_valid & ATTR_MTIME_SET){
+               attrs.ia_valid |= HOSTFS_ATTR_MTIME_SET;
+       }
+       name = dentry_name(dentry, 0);
+       if(name == NULL) return(-ENOMEM);
+       err = set_attr(name, &attrs);
+       kfree(name);
+       if(err)
+               return(err);
+
+       return(inode_setattr(dentry->d_inode, attr));
+}
+
+int hostfs_getattr(struct vfsmount *mnt, struct dentry *dentry, 
+          struct kstat *stat)
+{
+       generic_fillattr(dentry->d_inode, stat);
+       return(0);
+}
+
+static struct inode_operations hostfs_iops = {
+       .create         = hostfs_create,
+       .link           = hostfs_link,
+       .unlink         = hostfs_unlink,
+       .symlink        = hostfs_symlink,
+       .mkdir          = hostfs_mkdir,
+       .rmdir          = hostfs_rmdir,
+       .mknod          = hostfs_mknod,
+       .rename         = hostfs_rename,
+       .truncate       = hostfs_truncate,
+       .permission     = hostfs_permission,
+       .setattr        = hostfs_setattr,
+       .getattr        = hostfs_getattr,
+};
+
+static struct inode_operations hostfs_dir_iops = {
+       .create         = hostfs_create,
+       .lookup         = hostfs_lookup,
+       .link           = hostfs_link,
+       .unlink         = hostfs_unlink,
+       .symlink        = hostfs_symlink,
+       .mkdir          = hostfs_mkdir,
+       .rmdir          = hostfs_rmdir,
+       .mknod          = hostfs_mknod,
+       .rename         = hostfs_rename,
+       .truncate       = hostfs_truncate,
+       .permission     = hostfs_permission,
+       .setattr        = hostfs_setattr,
+       .getattr        = hostfs_getattr,
+};
+
+int hostfs_link_readpage(struct file *file, struct page *page)
+{
+       char *buffer, *name;
+       long long start;
+       int err;
+
+       start = page->index << PAGE_CACHE_SHIFT;
+       buffer = kmap(page);
+       name = inode_name(page->mapping->host, 0);
+       if(name == NULL) return(-ENOMEM);
+       err = do_readlink(name, buffer, PAGE_CACHE_SIZE);
+       kfree(name);
+       if(err == PAGE_CACHE_SIZE)
+               err = -E2BIG;
+       else if(err > 0){
+               flush_dcache_page(page);
+               SetPageUptodate(page);
+               if (PageError(page)) ClearPageError(page);
+               err = 0;
+       }
+       kunmap(page);
+       unlock_page(page);
+       return(err);
+}
+
+static struct address_space_operations hostfs_link_aops = {
+       .readpage       = hostfs_link_readpage,
+};
+
+static int hostfs_fill_sb_common(struct super_block *sb, void *d, int silent)
+{
+       struct inode *root_inode;
+       char *name, *data = d;
+       int err;
+
+       sb->s_blocksize = 1024;
+       sb->s_blocksize_bits = 10;
+       sb->s_magic = HOSTFS_SUPER_MAGIC;
+       sb->s_op = &hostfs_sbops;
+
+       if((data == NULL) || (*data == '\0')) 
+               data = root_ino;
+
+       err = -ENOMEM;
+       name = kmalloc(strlen(data) + 1, GFP_KERNEL);
+       if(name == NULL) 
+               goto out;
+
+       strcpy(name, data);
+
+       root_inode = iget(sb, 0);
+       if(root_inode == NULL)
+               goto out_free;
+
+       err = init_inode(root_inode, NULL);
+       if(err)
+               goto out_put;
+
+       HOSTFS_I(root_inode)->host_filename = name;
+
+       err = -ENOMEM;
+       sb->s_root = d_alloc_root(root_inode);
+       if(sb->s_root == NULL)
+               goto out_put;
+
+       err = read_inode(root_inode);
+       if(err)
+               goto out_put;
+
+       return(0);
+
+ out_put:
+       iput(root_inode);
+ out_free:
+       kfree(name);
+ out:
+       return(err);
+}
+
+static struct super_block *hostfs_read_sb(struct file_system_type *type,
+                                            int flags, const char *dev_name,
+                                            void *data)
+{
+       return(get_sb_nodev(type, flags, data, hostfs_fill_sb_common));
+}
+
+static struct file_system_type hostfs_type = {
+       .owner          = THIS_MODULE,
+       .name           = "hostfs",
+       .get_sb         = hostfs_read_sb,
+       .kill_sb        = kill_anon_super,
+       .fs_flags       = 0,
+};
+
+static int __init init_hostfs(void)
+{
+       return(register_filesystem(&hostfs_type));
+}
+
+static void __exit exit_hostfs(void)
+{
+       unregister_filesystem(&hostfs_type);
+}
+
+module_init(init_hostfs)
+module_exit(exit_hostfs)
+MODULE_LICENSE("GPL");
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff --git a/fs/hostfs/hostfs_user.c b/fs/hostfs/hostfs_user.c
new file mode 100644 (file)
index 0000000..c406266
--- /dev/null
@@ -0,0 +1,361 @@
+/* 
+ * Copyright (C) 2000 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#include <unistd.h>
+#include <stdio.h>
+#include <fcntl.h>
+#include <dirent.h>
+#include <errno.h>
+#include <utime.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <sys/vfs.h>
+#include "hostfs.h"
+#include "kern_util.h"
+#include "user.h"
+
+int stat_file(const char *path, unsigned long long *inode_out, int *mode_out,
+             int *nlink_out, int *uid_out, int *gid_out, 
+             unsigned long long *size_out, struct timespec *atime_out,
+             struct timespec *mtime_out, struct timespec *ctime_out,
+             int *blksize_out, unsigned long long *blocks_out)
+{
+       struct stat64 buf;
+
+       if(lstat64(path, &buf) < 0) 
+               return(-errno);
+
+       /* See the Makefile for why STAT64_INO_FIELD is passed in
+        * by the build
+        */
+       if(inode_out != NULL) *inode_out = buf.STAT64_INO_FIELD;
+       if(mode_out != NULL) *mode_out = buf.st_mode;
+       if(nlink_out != NULL) *nlink_out = buf.st_nlink;
+       if(uid_out != NULL) *uid_out = buf.st_uid;
+       if(gid_out != NULL) *gid_out = buf.st_gid;
+       if(size_out != NULL) *size_out = buf.st_size;
+       if(atime_out != NULL) {
+               atime_out->tv_sec = buf.st_atime;
+               atime_out->tv_nsec = 0;
+       }
+       if(mtime_out != NULL) {
+               mtime_out->tv_sec = buf.st_mtime;
+               mtime_out->tv_nsec = 0;
+       }
+       if(ctime_out != NULL) {
+               ctime_out->tv_sec = buf.st_ctime;
+               ctime_out->tv_nsec = 0;
+       }
+       if(blksize_out != NULL) *blksize_out = buf.st_blksize;
+       if(blocks_out != NULL) *blocks_out = buf.st_blocks;
+       return(0);
+}
+
+int file_type(const char *path, int *rdev)
+{
+       struct stat64 buf;
+
+       if(lstat64(path, &buf) < 0) 
+               return(-errno);
+       if(rdev != NULL) 
+               *rdev = buf.st_rdev;
+
+       if(S_ISDIR(buf.st_mode)) return(OS_TYPE_DIR);
+       else if(S_ISLNK(buf.st_mode)) return(OS_TYPE_SYMLINK);
+       else if(S_ISCHR(buf.st_mode)) return(OS_TYPE_CHARDEV);
+       else if(S_ISBLK(buf.st_mode)) return(OS_TYPE_BLOCKDEV);
+       else if(S_ISFIFO(buf.st_mode))return(OS_TYPE_FIFO);
+       else if(S_ISSOCK(buf.st_mode))return(OS_TYPE_SOCK);
+       else return(OS_TYPE_FILE);
+}
+
+int access_file(char *path, int r, int w, int x)
+{
+       int mode = 0;
+
+       if(r) mode = R_OK;
+       if(w) mode |= W_OK;
+       if(x) mode |= X_OK;
+       if(access(path, mode) != 0) return(-errno);
+       else return(0);
+}
+
+int open_file(char *path, int r, int w, int append)
+{
+       int mode = 0, fd;
+
+       if(r && !w) 
+               mode = O_RDONLY;
+       else if(!r && w) 
+               mode = O_WRONLY;
+       else if(r && w) 
+               mode = O_RDWR;
+       else panic("Impossible mode in open_file");
+
+       if(append)
+               mode |= O_APPEND;
+       fd = open64(path, mode);
+       if(fd < 0) return(-errno);
+       else return(fd);
+}
+
+void *open_dir(char *path, int *err_out)
+{
+       DIR *dir;
+
+       dir = opendir(path);
+       *err_out = errno;
+       if(dir == NULL) return(NULL);
+       return(dir);
+}
+
+char *read_dir(void *stream, unsigned long long *pos, 
+              unsigned long long *ino_out, int *len_out)
+{
+       DIR *dir = stream;
+       struct dirent *ent;
+
+       seekdir(dir, *pos);
+       ent = readdir(dir);
+       if(ent == NULL) return(NULL);
+       *len_out = strlen(ent->d_name);
+       *ino_out = ent->d_ino;
+       *pos = telldir(dir);
+       return(ent->d_name);
+}
+
+int read_file(int fd, unsigned long long *offset, char *buf, int len)
+{
+       int n;
+
+       n = pread64(fd, buf, len, *offset);
+       if(n < 0) return(-errno);
+       *offset += n;
+       return(n);
+}
+
+int write_file(int fd, unsigned long long *offset, const char *buf, int len)
+{
+       int n;
+
+       n = pwrite64(fd, buf, len, *offset);
+       if(n < 0) return(-errno);
+       *offset += n;
+       return(n);
+}
+
+int lseek_file(int fd, long long offset, int whence)
+{
+       int ret;
+
+       ret = lseek64(fd, offset, whence);
+       if(ret < 0) return(-errno);
+       return(0);
+}
+
+void close_file(void *stream)
+{
+       close(*((int *) stream));
+}
+
+void close_dir(void *stream)
+{
+       closedir(stream);
+}
+
+int file_create(char *name, int ur, int uw, int ux, int gr, 
+               int gw, int gx, int or, int ow, int ox)
+{
+       int mode, fd;
+
+       mode = 0;
+       mode |= ur ? S_IRUSR : 0;
+       mode |= uw ? S_IWUSR : 0;
+       mode |= ux ? S_IXUSR : 0;
+       mode |= gr ? S_IRGRP : 0;
+       mode |= gw ? S_IWGRP : 0;
+       mode |= gx ? S_IXGRP : 0;
+       mode |= or ? S_IROTH : 0;
+       mode |= ow ? S_IWOTH : 0;
+       mode |= ox ? S_IXOTH : 0;
+       fd = open64(name, O_CREAT | O_RDWR, mode);
+       if(fd < 0) 
+               return(-errno);
+       return(fd);
+}
+
+int set_attr(const char *file, struct hostfs_iattr *attrs)
+{
+       struct utimbuf buf;
+       int err, ma;
+
+       if(attrs->ia_valid & HOSTFS_ATTR_MODE){
+               if(chmod(file, attrs->ia_mode) != 0) return(-errno);
+       }
+       if(attrs->ia_valid & HOSTFS_ATTR_UID){
+               if(chown(file, attrs->ia_uid, -1)) return(-errno);
+       }
+       if(attrs->ia_valid & HOSTFS_ATTR_GID){
+               if(chown(file, -1, attrs->ia_gid)) return(-errno);
+       }
+       if(attrs->ia_valid & HOSTFS_ATTR_SIZE){
+               if(truncate(file, attrs->ia_size)) return(-errno);
+       }
+       ma = HOSTFS_ATTR_ATIME_SET | HOSTFS_ATTR_MTIME_SET;
+       if((attrs->ia_valid & ma) == ma){
+               buf.actime = attrs->ia_atime.tv_sec;
+               buf.modtime = attrs->ia_mtime.tv_sec;
+               if(utime(file, &buf) != 0) return(-errno);
+       }
+       else {
+               struct timespec ts;
+
+               if(attrs->ia_valid & HOSTFS_ATTR_ATIME_SET){
+                       err = stat_file(file, NULL, NULL, NULL, NULL, NULL, 
+                                       NULL, NULL, &ts, NULL, NULL, NULL);
+                       if(err != 0) 
+                               return(err);
+                       buf.actime = attrs->ia_atime.tv_sec;
+                       buf.modtime = ts.tv_sec;
+                       if(utime(file, &buf) != 0) 
+                               return(-errno);
+               }
+               if(attrs->ia_valid & HOSTFS_ATTR_MTIME_SET){
+                       err = stat_file(file, NULL, NULL, NULL, NULL, NULL, 
+                                       NULL, &ts, NULL, NULL, NULL, NULL);
+                       if(err != 0) 
+                               return(err);
+                       buf.actime = ts.tv_sec;
+                       buf.modtime = attrs->ia_mtime.tv_sec;
+                       if(utime(file, &buf) != 0) 
+                               return(-errno);
+               }
+       }
+       if(attrs->ia_valid & HOSTFS_ATTR_CTIME) ;
+       if(attrs->ia_valid & (HOSTFS_ATTR_ATIME | HOSTFS_ATTR_MTIME)){
+               err = stat_file(file, NULL, NULL, NULL, NULL, NULL, NULL, 
+                               &attrs->ia_atime, &attrs->ia_mtime, NULL, 
+                               NULL, NULL);
+               if(err != 0) return(err);
+       }
+       return(0);
+}
+
+int make_symlink(const char *from, const char *to)
+{
+       int err;
+
+       err = symlink(to, from);
+       if(err) return(-errno);
+       return(0);
+}
+
+int unlink_file(const char *file)
+{
+       int err;
+
+       err = unlink(file);
+       if(err) return(-errno);
+       return(0);
+}
+
+int do_mkdir(const char *file, int mode)
+{
+       int err;
+
+       err = mkdir(file, mode);
+       if(err) return(-errno);
+       return(0);
+}
+
+int do_rmdir(const char *file)
+{
+       int err;
+
+       err = rmdir(file);
+       if(err) return(-errno);
+       return(0);
+}
+
+int do_mknod(const char *file, int mode, int dev)
+{
+       int err;
+
+       err = mknod(file, mode, dev);
+       if(err) return(-errno);
+       return(0);
+}
+
+int link_file(const char *to, const char *from)
+{
+       int err;
+
+       err = link(to, from);
+       if(err) return(-errno);
+       return(0);
+}
+
+int do_readlink(char *file, char *buf, int size)
+{
+       int n;
+
+       n = readlink(file, buf, size);
+       if(n < 0) 
+               return(-errno);
+       if(n < size) 
+               buf[n] = '\0';
+       return(n);
+}
+
+int rename_file(char *from, char *to)
+{
+       int err;
+
+       err = rename(from, to);
+       if(err < 0) return(-errno);
+       return(0);      
+}
+
+int do_statfs(char *root, long *bsize_out, long long *blocks_out, 
+             long long *bfree_out, long long *bavail_out, 
+             long long *files_out, long long *ffree_out,
+             void *fsid_out, int fsid_size, long *namelen_out, 
+             long *spare_out)
+{
+       struct statfs64 buf;
+       int err;
+
+       err = statfs64(root, &buf);
+       if(err < 0) return(-errno);
+       *bsize_out = buf.f_bsize;
+       *blocks_out = buf.f_blocks;
+       *bfree_out = buf.f_bfree;
+       *bavail_out = buf.f_bavail;
+       *files_out = buf.f_files;
+       *ffree_out = buf.f_ffree;
+       memcpy(fsid_out, &buf.f_fsid, 
+              sizeof(buf.f_fsid) > fsid_size ? fsid_size : 
+              sizeof(buf.f_fsid));
+       *namelen_out = buf.f_namelen;
+       spare_out[0] = buf.f_spare[0];
+       spare_out[1] = buf.f_spare[1];
+       spare_out[2] = buf.f_spare[2];
+       spare_out[3] = buf.f_spare[3];
+       spare_out[4] = buf.f_spare[4];
+       spare_out[5] = buf.f_spare[5];
+       return(0);
+}
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff --git a/fs/hppfs/Makefile b/fs/hppfs/Makefile
new file mode 100644 (file)
index 0000000..e67f038
--- /dev/null
@@ -0,0 +1,19 @@
+# 
+# Copyright (C) 2002, 2003 Jeff Dike (jdike@karaya.com)
+# Licensed under the GPL
+#
+
+hppfs-objs := hppfs_kern.o
+
+obj-y = 
+obj-$(CONFIG_HPPFS) += hppfs.o
+
+clean:
+
+modules:
+
+fastdep:
+
+dep:
+
+archmrproper: clean
diff --git a/fs/hppfs/hppfs_kern.c b/fs/hppfs/hppfs_kern.c
new file mode 100644 (file)
index 0000000..ebf08cb
--- /dev/null
@@ -0,0 +1,811 @@
+/* 
+ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#include <linux/fs.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/list.h>
+#include <linux/kernel.h>
+#include <linux/ctype.h>
+#include <linux/dcache.h>
+#include <linux/statfs.h>
+#include <asm/uaccess.h>
+#include <asm/fcntl.h>
+#include "os.h"
+
+static int init_inode(struct inode *inode, struct dentry *dentry);
+
+struct hppfs_data {
+       struct list_head list;
+       char contents[PAGE_SIZE - sizeof(struct list_head)];
+};
+
+struct hppfs_private {
+       struct file proc_file;
+       int host_fd;
+       loff_t len;
+       struct hppfs_data *contents;
+};
+
+struct hppfs_inode_info {
+        struct dentry *proc_dentry;
+       struct inode vfs_inode;
+};
+
+static inline struct hppfs_inode_info *HPPFS_I(struct inode *inode)
+{
+       return(list_entry(inode, struct hppfs_inode_info, vfs_inode));
+}
+
+#define HPPFS_SUPER_MAGIC 0xb00000ee
+
+static struct super_operations hppfs_sbops;
+
+static int is_pid(struct dentry *dentry)
+{
+       struct super_block *sb;
+       int i;
+
+       sb = dentry->d_sb;
+       if((sb->s_op != &hppfs_sbops) || (dentry->d_parent != sb->s_root))
+               return(0);
+
+       for(i = 0; i < dentry->d_name.len; i++){
+               if(!isdigit(dentry->d_name.name[i]))
+                       return(0);
+       }
+       return(1);
+}
+
+static char *dentry_name(struct dentry *dentry, int extra)
+{
+       struct dentry *parent;
+       char *root, *name;
+       const char *seg_name;
+       int len, seg_len;
+
+       len = 0;
+       parent = dentry;
+       while(parent->d_parent != parent){
+               if(is_pid(parent))
+                       len += strlen("pid") + 1;
+               else len += parent->d_name.len + 1;
+               parent = parent->d_parent;
+       }
+       
+       root = "proc";
+       len += strlen(root);
+       name = kmalloc(len + extra + 1, GFP_KERNEL);
+       if(name == NULL) return(NULL);
+
+       name[len] = '\0';
+       parent = dentry;
+       while(parent->d_parent != parent){
+               if(is_pid(parent)){
+                       seg_name = "pid";
+                       seg_len = strlen("pid");
+               }
+               else {
+                       seg_name = parent->d_name.name;
+                       seg_len = parent->d_name.len;
+               }
+
+               len -= seg_len + 1;
+               name[len] = '/';
+               strncpy(&name[len + 1], seg_name, seg_len);
+               parent = parent->d_parent;
+       }
+       strncpy(name, root, strlen(root));
+       return(name);
+}
+
+struct dentry_operations hppfs_dentry_ops = {
+};
+
+static int file_removed(struct dentry *dentry, const char *file)
+{
+       char *host_file;
+       int extra, fd;
+
+       extra = 0;
+       if(file != NULL) extra += strlen(file) + 1;
+
+       host_file = dentry_name(dentry, extra + strlen("/remove"));
+       if(host_file == NULL){
+               printk("file_removed : allocation failed\n");
+               return(-ENOMEM);
+       }
+
+       if(file != NULL){
+               strcat(host_file, "/");
+               strcat(host_file, file);
+       }
+       strcat(host_file, "/remove");
+
+       fd = os_open_file(host_file, of_read(OPENFLAGS()), 0);
+       kfree(host_file);
+       if(fd > 0){
+               os_close_file(fd);
+               return(1);
+       }
+       return(0);
+}
+
+static void hppfs_read_inode(struct inode *ino)
+{
+       struct inode *proc_ino;
+
+       if(HPPFS_I(ino)->proc_dentry == NULL)
+               return;
+
+       proc_ino = HPPFS_I(ino)->proc_dentry->d_inode;
+       ino->i_uid = proc_ino->i_uid;
+       ino->i_gid = proc_ino->i_gid;
+       ino->i_atime = proc_ino->i_atime;
+       ino->i_mtime = proc_ino->i_mtime;
+       ino->i_ctime = proc_ino->i_ctime;
+       ino->i_ino = proc_ino->i_ino;
+       ino->i_mode = proc_ino->i_mode;
+       ino->i_nlink = proc_ino->i_nlink;
+       ino->i_size = proc_ino->i_size;
+       ino->i_blksize = proc_ino->i_blksize;
+       ino->i_blocks = proc_ino->i_blocks;
+}
+
+static struct dentry *hppfs_lookup(struct inode *ino, struct dentry *dentry, 
+                                  struct nameidata *nd)
+{
+       struct dentry *proc_dentry, *new, *parent;
+       struct inode *inode;
+       int err, deleted;
+
+       deleted = file_removed(dentry, NULL);
+       if(deleted < 0)
+               return(ERR_PTR(deleted));
+       else if(deleted)
+               return(ERR_PTR(-ENOENT));
+
+       err = -ENOMEM;
+       parent = HPPFS_I(ino)->proc_dentry;
+       down(&parent->d_inode->i_sem);
+       proc_dentry = d_lookup(parent, &dentry->d_name);
+       if(proc_dentry == NULL){
+               proc_dentry = d_alloc(parent, &dentry->d_name);
+               if(proc_dentry == NULL){
+                       up(&parent->d_inode->i_sem);
+                       goto out;
+               }
+               new = (*parent->d_inode->i_op->lookup)(parent->d_inode, 
+                                                      proc_dentry, NULL);
+               if(new){
+                       dput(proc_dentry);
+                       proc_dentry = new;
+               }
+       }
+       up(&parent->d_inode->i_sem);
+
+       if(IS_ERR(proc_dentry))
+               return(proc_dentry);
+
+       inode = iget(ino->i_sb, 0);
+       if(inode == NULL) 
+               goto out_dput;
+
+       err = init_inode(inode, proc_dentry);
+       if(err) 
+               goto out_put;
+       
+       hppfs_read_inode(inode);
+
+       d_add(dentry, inode);
+       dentry->d_op = &hppfs_dentry_ops;
+       return(NULL);
+
+ out_put:
+       iput(inode);
+ out_dput:
+       dput(proc_dentry);
+ out:
+       return(ERR_PTR(err));
+}
+
+static struct inode_operations hppfs_file_iops = {
+};
+
+static ssize_t read_proc(struct file *file, char *buf, ssize_t count, 
+                        loff_t *ppos, int is_user)
+{
+       ssize_t (*read)(struct file *, char *, size_t, loff_t *);
+       ssize_t n;
+
+       read = file->f_dentry->d_inode->i_fop->read;
+
+       if(!is_user)
+               set_fs(KERNEL_DS);
+               
+       n = (*read)(file, buf, count, &file->f_pos);
+
+       if(!is_user)
+               set_fs(USER_DS);
+
+       if(ppos) *ppos = file->f_pos;
+       return(n);
+}
+
+static ssize_t hppfs_read_file(int fd, char *buf, ssize_t count)
+{
+       ssize_t n;
+       int cur, err;
+       char *new_buf;
+
+       n = -ENOMEM;
+       new_buf = kmalloc(PAGE_SIZE, GFP_KERNEL);
+       if(new_buf == NULL){
+               printk("hppfs_read_file : kmalloc failed\n");
+               goto out;
+       }
+       n = 0;
+       while(count > 0){
+               cur = min_t(ssize_t, count, PAGE_SIZE);
+               err = os_read_file(fd, new_buf, cur);
+               if(err < 0){
+                       printk("hppfs_read : read failed, errno = %d\n",
+                              count);
+                       n = err;
+                       goto out_free;
+               }
+               else if(err == 0)
+                       break;
+
+               if(copy_to_user(buf, new_buf, err)){
+                       n = -EFAULT;
+                       goto out_free;
+               }
+               n += err;
+               count -= err;
+       }
+ out_free:
+       kfree(new_buf);
+ out:
+       return(n);
+}
+
+static ssize_t hppfs_read(struct file *file, char *buf, size_t count, 
+                         loff_t *ppos)
+{
+       struct hppfs_private *hppfs = file->private_data;
+       struct hppfs_data *data;
+       loff_t off;
+       int err;
+
+       if(hppfs->contents != NULL){
+               if(*ppos >= hppfs->len) return(0);
+
+               data = hppfs->contents;
+               off = *ppos;
+               while(off >= sizeof(data->contents)){
+                       data = list_entry(data->list.next, struct hppfs_data,
+                                         list);
+                       off -= sizeof(data->contents);
+               }
+
+               if(off + count > hppfs->len)
+                       count = hppfs->len - off;
+               copy_to_user(buf, &data->contents[off], count);
+               *ppos += count;
+       }
+       else if(hppfs->host_fd != -1){
+               err = os_seek_file(hppfs->host_fd, *ppos);
+               if(err){
+                       printk("hppfs_read : seek failed, errno = %d\n", err);
+                       return(err);
+               }
+               count = hppfs_read_file(hppfs->host_fd, buf, count);
+               if(count > 0)
+                       *ppos += count;
+       }
+       else count = read_proc(&hppfs->proc_file, buf, count, ppos, 1);
+
+       return(count);
+}
+
+static ssize_t hppfs_write(struct file *file, const char *buf, size_t len, 
+                          loff_t *ppos)
+{
+       struct hppfs_private *data = file->private_data;
+       struct file *proc_file = &data->proc_file;
+       ssize_t (*write)(struct file *, const char *, size_t, loff_t *);
+       int err;
+
+       write = proc_file->f_dentry->d_inode->i_fop->write;
+
+       proc_file->f_pos = file->f_pos;
+       err = (*write)(proc_file, buf, len, &proc_file->f_pos);
+       file->f_pos = proc_file->f_pos;
+
+       return(err);
+}
+
+static int open_host_sock(char *host_file, int *filter_out)
+{
+       char *end;
+       int fd;
+
+       end = &host_file[strlen(host_file)];
+       strcpy(end, "/rw");
+       *filter_out = 1;
+       fd = os_connect_socket(host_file);
+       if(fd > 0)
+               return(fd);
+
+       strcpy(end, "/r");
+       *filter_out = 0;
+       fd = os_connect_socket(host_file);
+       return(fd);
+}
+
+static void free_contents(struct hppfs_data *head)
+{
+       struct hppfs_data *data;
+       struct list_head *ele, *next;
+
+       if(head == NULL) return;
+
+       list_for_each_safe(ele, next, &head->list){
+               data = list_entry(ele, struct hppfs_data, list);
+               kfree(data);
+       }
+       kfree(head);
+}
+
+static struct hppfs_data *hppfs_get_data(int fd, int filter, 
+                                        struct file *proc_file, 
+                                        struct file *hppfs_file, 
+                                        loff_t *size_out)
+{
+       struct hppfs_data *data, *new, *head;
+       int n, err;
+
+       err = -ENOMEM;
+       data = kmalloc(sizeof(*data), GFP_KERNEL);
+       if(data == NULL){
+               printk("hppfs_get_data : head allocation failed\n");
+               goto failed;
+       }
+
+       INIT_LIST_HEAD(&data->list);
+
+       head = data;
+       *size_out = 0;
+
+       if(filter){
+               while((n = read_proc(proc_file, data->contents,
+                                    sizeof(data->contents), NULL, 0)) > 0)
+                       os_write_file(fd, data->contents, n);
+               err = os_shutdown_socket(fd, 0, 1);
+               if(err){
+                       printk("hppfs_get_data : failed to shut down "
+                              "socket\n");
+                       goto failed_free;
+               }
+       }
+       while(1){
+               n = os_read_file(fd, data->contents, sizeof(data->contents));
+               if(n < 0){
+                       err = n;
+                       printk("hppfs_get_data : read failed, errno = %d\n",
+                              err);
+                       goto failed_free;
+               }
+               else if(n == 0)
+                       break;
+
+               *size_out += n;
+
+               if(n < sizeof(data->contents))
+                       break;
+
+               new = kmalloc(sizeof(*data), GFP_KERNEL);
+               if(new == 0){
+                       printk("hppfs_get_data : data allocation failed\n");
+                       err = -ENOMEM;
+                       goto failed_free;
+               }
+       
+               INIT_LIST_HEAD(&new->list);
+               list_add(&new->list, &data->list);
+               data = new;
+       }
+       return(head);
+
+ failed_free:
+       free_contents(head);
+ failed:               
+       return(ERR_PTR(err));
+}
+
+static struct hppfs_private *hppfs_data(void)
+{
+       struct hppfs_private *data;
+
+       data = kmalloc(sizeof(*data), GFP_KERNEL);
+       if(data == NULL)
+               return(data);
+
+       *data = ((struct hppfs_private ) { .host_fd             = -1,
+                                          .len                 = -1,
+                                          .contents            = NULL } );
+       return(data);
+}
+
+static int file_mode(int fmode)
+{
+       if(fmode == (FMODE_READ | FMODE_WRITE))
+               return(O_RDWR);
+       if(fmode == FMODE_READ)
+               return(O_RDONLY);
+       if(fmode == FMODE_WRITE)
+               return(O_WRONLY);
+       return(0);
+}
+
+static int hppfs_open(struct inode *inode, struct file *file)
+{
+       struct hppfs_private *data;
+       struct dentry *proc_dentry;
+       char *host_file;
+       int err, fd, type, filter;
+
+       err = -ENOMEM;
+       data = hppfs_data();
+       if(data == NULL)
+               goto out;
+
+       host_file = dentry_name(file->f_dentry, strlen("/rw"));
+       if(host_file == NULL)
+               goto out_free2;
+
+       proc_dentry = HPPFS_I(inode)->proc_dentry;
+
+       /* XXX This isn't closed anywhere */
+       err = open_private_file(&data->proc_file, proc_dentry, 
+                               file_mode(file->f_mode));
+       if(err)
+               goto out_free1;
+
+       type = os_file_type(host_file);
+       if(type == OS_TYPE_FILE){
+               fd = os_open_file(host_file, of_read(OPENFLAGS()), 0);
+               if(fd >= 0) 
+                       data->host_fd = fd;
+               else printk("hppfs_open : failed to open '%s', errno = %d\n",
+                           host_file, -fd);
+
+               data->contents = NULL;
+       }
+       else if(type == OS_TYPE_DIR){
+               fd = open_host_sock(host_file, &filter);
+               if(fd > 0){
+                       data->contents = hppfs_get_data(fd, filter, 
+                                                       &data->proc_file, 
+                                                       file, &data->len);
+                       if(!IS_ERR(data->contents))
+                               data->host_fd = fd;
+               }
+               else printk("hppfs_open : failed to open a socket in "
+                           "'%s', errno = %d\n", host_file, -fd);
+       }
+       kfree(host_file);
+
+       file->private_data = data;
+       return(0);
+
+ out_free1:
+       kfree(host_file);
+ out_free2:
+       free_contents(data->contents);
+       kfree(data);
+ out:
+       return(err);
+}
+
+static int hppfs_dir_open(struct inode *inode, struct file *file)
+{
+       struct hppfs_private *data;
+       struct dentry *proc_dentry;
+       int err;
+
+       err = -ENOMEM;
+       data = hppfs_data();
+       if(data == NULL)
+               goto out;
+
+       proc_dentry = HPPFS_I(inode)->proc_dentry;
+       err = open_private_file(&data->proc_file, proc_dentry, 
+                               file_mode(file->f_mode));
+       if(err)
+               goto out_free;
+
+       file->private_data = data;
+       return(0);
+
+ out_free:
+       kfree(data);
+ out:
+       return(err);
+}
+
+static loff_t hppfs_llseek(struct file *file, loff_t off, int where)
+{
+       struct hppfs_private *data = file->private_data;
+       struct file *proc_file = &data->proc_file;
+       loff_t (*llseek)(struct file *, loff_t, int);
+       loff_t ret;
+
+       llseek = proc_file->f_dentry->d_inode->i_fop->llseek;
+       if(llseek != NULL){
+               ret = (*llseek)(proc_file, off, where);
+               if(ret < 0)
+                       return(ret);
+       }
+
+       return(default_llseek(file, off, where));
+}
+
+static struct file_operations hppfs_file_fops = {
+       .owner          = NULL,
+       .llseek         = hppfs_llseek,
+       .read           = hppfs_read,
+       .write          = hppfs_write,
+       .open           = hppfs_open,
+};
+
+struct hppfs_dirent {
+       void *vfs_dirent;
+       filldir_t filldir;
+       struct dentry *dentry;
+};
+
+static int hppfs_filldir(void *d, const char *name, int size, 
+                        loff_t offset, ino_t inode, unsigned int type)
+{
+       struct hppfs_dirent *dirent = d;
+
+       if(file_removed(dirent->dentry, name))
+               return(0);
+
+       return((*dirent->filldir)(dirent->vfs_dirent, name, size, offset, 
+                                 inode, type));
+}
+
+static int hppfs_readdir(struct file *file, void *ent, filldir_t filldir)
+{
+       struct hppfs_private *data = file->private_data;
+       struct file *proc_file = &data->proc_file;
+       int (*readdir)(struct file *, void *, filldir_t);
+       struct hppfs_dirent dirent = ((struct hppfs_dirent)
+                                     { .vfs_dirent     = ent,
+                                       .filldir        = filldir,
+                                       .dentry         = file->f_dentry } );
+       int err;
+
+       readdir = proc_file->f_dentry->d_inode->i_fop->readdir;
+
+       proc_file->f_pos = file->f_pos;
+       err = (*readdir)(proc_file, &dirent, hppfs_filldir);
+       file->f_pos = proc_file->f_pos;
+
+       return(err);
+}
+
+static int hppfs_fsync(struct file *file, struct dentry *dentry, int datasync)
+{
+       return(0);
+}
+
+static struct file_operations hppfs_dir_fops = {
+       .owner          = NULL,
+       .readdir        = hppfs_readdir,
+       .open           = hppfs_dir_open,
+       .fsync          = hppfs_fsync,
+};
+
+static int hppfs_statfs(struct super_block *sb, struct kstatfs *sf)
+{
+       sf->f_blocks = 0;
+       sf->f_bfree = 0;
+       sf->f_bavail = 0;
+       sf->f_files = 0;
+       sf->f_ffree = 0;
+       sf->f_type = HPPFS_SUPER_MAGIC;
+       return(0);
+}
+
+static struct inode *hppfs_alloc_inode(struct super_block *sb)
+{
+       struct hppfs_inode_info *hi;
+
+       hi = kmalloc(sizeof(*hi), GFP_KERNEL);
+       if(hi == NULL) 
+               return(NULL);
+
+       *hi = ((struct hppfs_inode_info) { .proc_dentry = NULL });
+       inode_init_once(&hi->vfs_inode);
+       return(&hi->vfs_inode);
+}
+
+void hppfs_delete_inode(struct inode *ino)
+{
+       clear_inode(ino);
+}
+
+static void hppfs_destroy_inode(struct inode *inode)
+{
+       kfree(HPPFS_I(inode));
+}
+
+static struct super_operations hppfs_sbops = { 
+       .alloc_inode    = hppfs_alloc_inode,
+       .destroy_inode  = hppfs_destroy_inode,
+       .read_inode     = hppfs_read_inode,
+       .delete_inode   = hppfs_delete_inode,
+       .statfs         = hppfs_statfs,
+};
+
+static int hppfs_readlink(struct dentry *dentry, char *buffer, int buflen)
+{
+       struct file proc_file;
+       struct dentry *proc_dentry;
+       int (*readlink)(struct dentry *, char *, int);
+       int err, n;
+
+       proc_dentry = HPPFS_I(dentry->d_inode)->proc_dentry;
+       err = open_private_file(&proc_file, proc_dentry, O_RDONLY);
+       if(err) 
+               return(err);
+
+       readlink = proc_dentry->d_inode->i_op->readlink;
+       n = (*readlink)(proc_dentry, buffer, buflen);
+
+       close_private_file(&proc_file);
+       
+       return(n);
+}
+
+static int hppfs_follow_link(struct dentry *dentry, struct nameidata *nd)
+{
+       struct file proc_file;
+       struct dentry *proc_dentry;
+       int (*follow_link)(struct dentry *, struct nameidata *);
+       int err, n;
+
+       proc_dentry = HPPFS_I(dentry->d_inode)->proc_dentry;
+       err = open_private_file(&proc_file, proc_dentry, O_RDONLY);
+       if(err) 
+               return(err);
+
+       follow_link = proc_dentry->d_inode->i_op->follow_link;
+       n = (*follow_link)(proc_dentry, nd);
+
+       close_private_file(&proc_file);
+       
+       return(n);
+}
+
+static struct inode_operations hppfs_dir_iops = {
+       .lookup         = hppfs_lookup,
+};
+
+static struct inode_operations hppfs_link_iops = {
+       .readlink       = hppfs_readlink,
+       .follow_link    = hppfs_follow_link,
+};
+
+static int init_inode(struct inode *inode, struct dentry *dentry)
+{
+       if(S_ISDIR(dentry->d_inode->i_mode)){
+               inode->i_op = &hppfs_dir_iops;
+               inode->i_fop = &hppfs_dir_fops;
+       }
+       else if(S_ISLNK(dentry->d_inode->i_mode)){
+               inode->i_op = &hppfs_link_iops;
+               inode->i_fop = &hppfs_file_fops;
+       }
+       else {
+               inode->i_op = &hppfs_file_iops;
+               inode->i_fop = &hppfs_file_fops;
+       }
+
+       HPPFS_I(inode)->proc_dentry = dentry;
+
+       return(0);
+}
+
+static int hppfs_fill_super(struct super_block *sb, void *d, int silent)
+{
+       struct inode *root_inode;
+       struct file_system_type *procfs;
+       struct super_block *proc_sb;
+       int err;
+
+       err = -ENOENT;
+       procfs = get_fs_type("proc");
+       if(procfs == NULL) 
+               goto out;
+
+       if(list_empty(&procfs->fs_supers))
+               goto out;
+
+       proc_sb = list_entry(procfs->fs_supers.next, struct super_block,
+                            s_instances);
+       
+       sb->s_blocksize = 1024;
+       sb->s_blocksize_bits = 10;
+       sb->s_magic = HPPFS_SUPER_MAGIC;
+       sb->s_op = &hppfs_sbops;
+
+       root_inode = iget(sb, 0);
+       if(root_inode == NULL)
+               goto out;
+
+       err = init_inode(root_inode, proc_sb->s_root);
+       if(err)
+               goto out_put;
+
+       err = -ENOMEM;
+       sb->s_root = d_alloc_root(root_inode);
+       if(sb->s_root == NULL)
+               goto out_put;
+
+       hppfs_read_inode(root_inode);
+
+       return(0);
+
+ out_put:
+       iput(root_inode);
+ out:
+       return(err);
+}
+
+static struct super_block *hppfs_read_super(struct file_system_type *type,
+                                            int flags, const char *dev_name,
+                                            void *data)
+{
+       return(get_sb_nodev(type, flags, data, hppfs_fill_super));
+}
+
+static struct file_system_type hppfs_type = {
+       .owner          = THIS_MODULE,
+       .name           = "hppfs",
+       .get_sb         = hppfs_read_super,
+       .kill_sb        = kill_anon_super,
+       .fs_flags       = 0,
+};
+
+static int __init init_hppfs(void)
+{
+       return(register_filesystem(&hppfs_type));
+}
+
+static void __exit exit_hppfs(void)
+{
+       unregister_filesystem(&hppfs_type);
+}
+
+module_init(init_hppfs)
+module_exit(exit_hppfs)
+MODULE_LICENSE("GPL");
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
index dddc722..1093bac 100644 (file)
@@ -683,7 +683,6 @@ static inline struct page *get_page_map(struct page *page)
 }
 
 
-#ifdef FIXADDR_START
 static struct vm_area_struct fixmap_vma = {
        /* Catch users - if there are any valid
           ones, we can make this be "&init_mm" or
@@ -701,7 +700,6 @@ static int init_fixmap_vma(void)
 }
 
 __initcall(init_fixmap_vma);
-#endif
 
 int get_user_pages(struct task_struct *tsk, struct mm_struct *mm,
                unsigned long start, int len, int write, int force,