[linux-yocto] [PATCH 10/87] fs/vmfs: adding arm vmfs patch
Bruce Ashfield
bruce.ashfield at windriver.com
Mon May 27 11:04:00 PDT 2013
On 13-05-27 12:55 PM, Paul Butler wrote:
The commit log should tell us something about what a "vmfs" is. I have
no idea without reading the patch, and that's not a good thing.
Bruce
> Signed-off-by: Paul Butler <paul.butler at windriver.com>
> ---
> arch/arm/include/asm/lsi/acp_ncr.h | 42 ++
> fs/Kconfig | 16 +
> fs/Makefile | 5 +-
> fs/vmfs/Makefile | 39 ++
> fs/vmfs/cache.c | 235 ++++++++
> fs/vmfs/dir.c | 626 +++++++++++++++++++++
> fs/vmfs/file.c | 500 +++++++++++++++++
> fs/vmfs/getopt.c | 67 +++
> fs/vmfs/getopt.h | 14 +
> fs/vmfs/inode.c | 653 ++++++++++++++++++++++
> fs/vmfs/ioctl.c | 49 ++
> fs/vmfs/mboxtypes.h | 31 +
> fs/vmfs/messagebox.c | 314 +++++++++++
> fs/vmfs/messagebox.h | 121 ++++
> fs/vmfs/msg.c | 232 ++++++++
> fs/vmfs/msg.h | 182 ++++++
> fs/vmfs/proc.c | 1086 ++++++++++++++++++++++++++++++++++++
> fs/vmfs/proto.h | 71 +++
> fs/vmfs/symlink.c | 68 +++
> fs/vmfs/vfs.c | 577 +++++++++++++++++++
> fs/vmfs/vfs.h | 356 ++++++++++++
> fs/vmfs/vmfs.h | 44 ++
> fs/vmfs/vmfs_debug.h | 39 ++
> fs/vmfs/vmfs_fs.h | 111 ++++
> fs/vmfs/vmfs_fs_i.h | 39 ++
> fs/vmfs/vmfs_fs_sb.h | 64 +++
> fs/vmfs/vmfs_mount.h | 62 ++
> fs/vmfs/vmfsno.h | 138 +++++
> 28 files changed, 5779 insertions(+), 2 deletions(-)
> create mode 100644 arch/arm/include/asm/lsi/acp_ncr.h
> create mode 100644 fs/vmfs/Makefile
> create mode 100644 fs/vmfs/cache.c
> create mode 100644 fs/vmfs/dir.c
> create mode 100644 fs/vmfs/file.c
> create mode 100644 fs/vmfs/getopt.c
> create mode 100644 fs/vmfs/getopt.h
> create mode 100644 fs/vmfs/inode.c
> create mode 100644 fs/vmfs/ioctl.c
> create mode 100644 fs/vmfs/mboxtypes.h
> create mode 100644 fs/vmfs/messagebox.c
> create mode 100644 fs/vmfs/messagebox.h
> create mode 100644 fs/vmfs/msg.c
> create mode 100644 fs/vmfs/msg.h
> create mode 100644 fs/vmfs/proc.c
> create mode 100644 fs/vmfs/proto.h
> create mode 100644 fs/vmfs/symlink.c
> create mode 100644 fs/vmfs/vfs.c
> create mode 100644 fs/vmfs/vfs.h
> create mode 100644 fs/vmfs/vmfs.h
> create mode 100644 fs/vmfs/vmfs_debug.h
> create mode 100644 fs/vmfs/vmfs_fs.h
> create mode 100644 fs/vmfs/vmfs_fs_i.h
> create mode 100644 fs/vmfs/vmfs_fs_sb.h
> create mode 100644 fs/vmfs/vmfs_mount.h
> create mode 100644 fs/vmfs/vmfsno.h
>
> diff --git a/arch/arm/include/asm/lsi/acp_ncr.h b/arch/arm/include/asm/lsi/acp_ncr.h
> new file mode 100644
> index 0000000..a7399e7
> --- /dev/null
> +++ b/arch/arm/include/asm/lsi/acp_ncr.h
> @@ -0,0 +1,42 @@
> +/*
> + * asm/lsi/acp_ncr.h
> + *
> + * Copyright (C) 2010 LSI
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License as published by
> + * the Free Software Foundation; either version 2 of the License, or
> + * (at your option) any later version.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> + * GNU General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with this program; if not, write to the Free Software
> + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
> + */
> +
> +#ifndef __DRIVERS_LSI_ACP_NCR_H
> +#define __DRIVERS_LSI_ACP_NCR_H
> +
> +#ifndef NCP_REGION_ID
> +#define NCP_REGION_ID(node, target) \
> +(unsigned long)((((node) & 0xffff) << 16) | ((target) & 0xffff))
> +#endif
> +
> +#ifndef NCP_NODE_ID
> +#define NCP_NODE_ID(region) (((region) >> 16) & 0xffff)
> +#endif
> +
> +#ifndef NCP_TARGET_ID
> +#define NCP_TARGET_ID(region) ((region) & 0xffff)
> +#endif
> +
> +int ncr_read(unsigned long, unsigned long, int, void *);
> +int ncr_write(unsigned long, unsigned long, int, void *);
> +
> +int is_asic(void);
> +
> +#endif /* __DRIVERS_LSI_ACP_NCR_H */
> diff --git a/fs/Kconfig b/fs/Kconfig
> index df7f99e..df7dd95c 100644
> --- a/fs/Kconfig
> +++ b/fs/Kconfig
> @@ -281,4 +281,20 @@ endif # NETWORK_FILESYSTEMS
> source "fs/nls/Kconfig"
> source "fs/dlm/Kconfig"
>
> +config VMFS_FS
> + tristate "VMFS file system support (to mount host directories etc.)"
> + select NLS
> + help
> + Say Y here to enable support for accessing the host filesystem
> + when running the kernel in a virtual platform built with the Fast
> + Models product from ARM.
> +
> +config VMFS_DEV_BASE
> + hex "VMFS base address"
> + depends on VMFS_FS
> +
> +config VMFS_IRQ
> + int "VMFS IRQ"
> + depends on VMFS_FS
> +
> endmenu
> diff --git a/fs/Makefile b/fs/Makefile
> index b182709..0158e43 100644
> --- a/fs/Makefile
> +++ b/fs/Makefile
> @@ -3,7 +3,7 @@
> #
> # 14 Sep 2000, Christoph Hellwig <hch at infradead.org>
> # Rewritten to use lists instead of if-statements.
> -#
> +#
>
> obj-y := open.o read_write.o file_table.o super.o \
> char_dev.o stat.o exec.o pipe.o namei.o fcntl.o \
> @@ -60,7 +60,7 @@ obj-y += devpts/
>
> obj-$(CONFIG_PROFILING) += dcookies.o
> obj-$(CONFIG_DLM) += dlm/
> -
> +
> # Do not add any filesystems before this line
> obj-$(CONFIG_FSCACHE) += fscache/
> obj-$(CONFIG_REISERFS_FS) += reiserfs/
> @@ -129,3 +129,4 @@ obj-$(CONFIG_CEPH_FS) += ceph/
> obj-$(CONFIG_PSTORE) += pstore/
> obj-$(CONFIG_YAFFS_FS) += yaffs2/
> obj-$(CONFIG_PRAMFS) += pramfs/
> +obj-$(CONFIG_VMFS_FS) += vmfs/
> diff --git a/fs/vmfs/Makefile b/fs/vmfs/Makefile
> new file mode 100644
> index 0000000..e74d18d
> --- /dev/null
> +++ b/fs/vmfs/Makefile
> @@ -0,0 +1,39 @@
> +#
> +# Makefile for the linux vmfs-filesystem routines.
> +#
> +
> +obj-$(CONFIG_VMFS_FS) += vmfsfs.o
> +
> +vmfsfs-objs := proc.o dir.o cache.o inode.o file.o ioctl.o getopt.o \
> + symlink.o messagebox.o msg.o vfs.o
> +
> +# If you want debugging output, you may add these flags to the EXTRA_CFLAGS
> +# VMFSFS_PARANOIA should normally be enabled.
> +
> +#EXTRA_CFLAGS += -DVMFSFS_PARANOIA
> +#EXTRA_CFLAGS += -DVMFSFS_DEBUG
> +#EXTRA_CFLAGS += -DVMFSFS_DEBUG_VERBOSE
> +#EXTRA_CFLAGS += -DMESSAGEBOX_DEBUG
> +#EXTRA_CFLAGS += -DDEBUG_VMFS_TIMESTAMP
> +#EXTRA_CFLAGS += -Werror
> +
> +#
> +# Maintainer rules
> +#
> +
> +# getopt.c not included. It is intentionally separate
> +SRC = proc.c dir.c cache.c inode.c file.c ioctl.c \
> + symlink.c
> +
> +proto:
> + -rm -f proto.h
> + @echo > proto2.h "/*"
> + @echo >> proto2.h " * Autogenerated with cproto on: " `date`
> + @echo >> proto2.h " */"
> + @echo >> proto2.h ""
> + @echo >> proto2.h "struct vmfs_request;"
> + @echo >> proto2.h "struct sock;"
> + @echo >> proto2.h "struct statfs;"
> + @echo >> proto2.h ""
> + cproto -E "gcc -E" -e -v -I $(TOPDIR)/include -DMAKING_PROTO -D__KERNEL__ $(SRC) >> proto2.h
> + mv proto2.h proto.h
> diff --git a/fs/vmfs/cache.c b/fs/vmfs/cache.c
> new file mode 100644
> index 0000000..b667698
> --- /dev/null
> +++ b/fs/vmfs/cache.c
> @@ -0,0 +1,235 @@
> +/*
> + * cache.c
> + *
> + * Copyright (C) 1997 by Bill Hawes
> + *
> + * Routines to support directory cacheing using the page cache.
> + * This cache code is almost directly taken from ncpfs.
> + *
> + * Please add a note about your changes to vmfs_ in the ChangeLog file.
> + */
> +
> +#include <linux/time.h>
> +#include <linux/errno.h>
> +#include <linux/kernel.h>
> +#include <linux/mm.h>
> +#include <linux/dirent.h>
> +#include "vmfs_fs.h"
> +#include <linux/pagemap.h>
> +#include <linux/net.h>
> +#include <linux/version.h>
> +
> +#include <asm/page.h>
> +
> +#include "vmfs_debug.h"
> +#include "proto.h"
> +
> +/*
> + * Force the next attempt to use the cache to be a timeout.
> + * If we can't find the page that's fine, it will cause a refresh.
> + */
> +void vmfs_invalid_dir_cache(struct inode *dir)
> +{
> + struct vmfs_sb_info *server = server_from_inode(dir);
> + union vmfs_dir_cache *cache = NULL;
> + struct page *page = NULL;
> +
> + page = grab_cache_page(&dir->i_data, 0);
> + if (!page)
> + goto out;
> +
> + if (!PageUptodate(page))
> + goto out_unlock;
> +
> + cache = kmap(page);
> + cache->head.time = jiffies - VMFS_MAX_AGE(server);
> +
> + kunmap(page);
> + SetPageUptodate(page);
> +out_unlock:
> + unlock_page(page);
> + page_cache_release(page);
> +out:
> + return;
> +}
> +
> +/*
> + * Mark all dentries for 'parent' as invalid, forcing them to be re-read
> + */
> +void vmfs_invalidate_dircache_entries(struct dentry *parent)
> +{
> + struct vmfs_sb_info *server = server_from_dentry(parent);
> + struct list_head *next;
> + struct dentry *dentry;
> +
> +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 38)
> + spin_lock(&dcache_lock);
> +#else
> + spin_lock(&parent->d_lock);
> +#endif
> + next = parent->d_subdirs.next;
> + while (next != &parent->d_subdirs) {
> + dentry = list_entry(next, struct dentry, d_u.d_child);
> + dentry->d_fsdata = NULL;
> + vmfs_age_dentry(server, dentry);
> + next = next->next;
> + }
> +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 38)
> + spin_unlock(&dcache_lock);
> +#else
> + spin_unlock(&parent->d_lock);
> +#endif
> +}
> +
> +/*
> + * dget, but require that fpos and parent matches what the dentry contains.
> + * dentry is not known to be a valid pointer at entry.
> + */
> +struct dentry *vmfs_dget_fpos(struct dentry *dentry, struct dentry *parent,
> + unsigned long fpos)
> +{
> + struct dentry *dent = dentry;
> + struct list_head *next;
> +
> + if (d_validate(dent, parent)) {
> + if (dent->d_name.len <= VMFS_MAXNAMELEN &&
> + (unsigned long)dent->d_fsdata == fpos) {
> + if (!dent->d_inode) {
> + dput(dent);
> + dent = NULL;
> + }
> + return dent;
> + }
> + dput(dent);
> + }
> +
> + /* If a pointer is invalid, we search the dentry. */
> +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 38)
> + spin_lock(&dcache_lock);
> +#else
> + spin_lock(&parent->d_lock);
> +#endif
> + next = parent->d_subdirs.next;
> + while (next != &parent->d_subdirs) {
> + dent = list_entry(next, struct dentry, d_u.d_child);
> + if ((unsigned long)dent->d_fsdata == fpos) {
> + if (dent->d_inode) {
> +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 38)
> + dget_locked(dent);
> +#else
> + dget(dent);
> +#endif
> + } else {
> + dent = NULL;
> + }
> + goto out_unlock;
> + }
> + next = next->next;
> + }
> + dent = NULL;
> +out_unlock:
> +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 38)
> + spin_unlock(&dcache_lock);
> +#else
> + spin_unlock(&parent->d_lock);
> +#endif
> + return dent;
> +}
> +
> +/*
> + * Create dentry/inode for this file and add it to the dircache.
> + */
> +int
> +vmfs_fill_cache(struct file *filp, void *dirent, filldir_t filldir,
> + struct vmfs_cache_control *ctrl, struct qstr *qname,
> + struct vmfs_fattr *entry)
> +{
> + struct dentry *newdent, *dentry = filp->f_path.dentry;
> + struct inode *newino, *inode = dentry->d_inode;
> + struct vmfs_cache_control ctl = *ctrl;
> + int valid = 0;
> + int hashed = 0;
> + ino_t ino = 0;
> +
> + DEBUG1("name=%s\n", qname->name);
> +
> + qname->hash = full_name_hash(qname->name, qname->len);
> +
> + if (dentry->d_op && dentry->d_op->d_hash) {
> +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 38)
> + if (dentry->d_op->d_hash(dentry, qname) != 0)
> +#else
> + if (dentry->d_op->d_hash(dentry, inode, qname) != 0)
> +#endif
> + goto end_advance;
> + }
> +
> + newdent = d_lookup(dentry, qname);
> +
> + if (!newdent) {
> + newdent = d_alloc(dentry, qname);
> + if (!newdent)
> + goto end_advance;
> + } else {
> + hashed = 1;
> + memcpy((char *)newdent->d_name.name, qname->name,
> + newdent->d_name.len);
> + }
> +
> + if (!newdent->d_inode) {
> + vmfs_renew_times(newdent);
> + entry->f_ino = iunique(inode->i_sb, 2);
> + newino = vmfs_iget(inode->i_sb, entry);
> + if (newino) {
> + vmfs_new_dentry(newdent);
> + d_instantiate(newdent, newino);
> + if (!hashed)
> + d_rehash(newdent);
> + }
> + } else
> + vmfs_set_inode_attr(newdent->d_inode, entry);
> +
> + if (newdent->d_inode) {
> + ino = newdent->d_inode->i_ino;
> + newdent->d_fsdata = (void *)ctl.fpos;
> + vmfs_new_dentry(newdent);
> + }
> +
> + if (ctl.idx >= VMFS_DIRCACHE_SIZE) {
> + if (ctl.page) {
> + kunmap(ctl.page);
> + SetPageUptodate(ctl.page);
> + unlock_page(ctl.page);
> + page_cache_release(ctl.page);
> + }
> + ctl.cache = NULL;
> + ctl.idx -= VMFS_DIRCACHE_SIZE;
> + ctl.ofs += 1;
> + ctl.page = grab_cache_page(&inode->i_data, ctl.ofs);
> + if (ctl.page)
> + ctl.cache = kmap(ctl.page);
> + }
> + if (ctl.cache) {
> + ctl.cache->dentry[ctl.idx] = newdent;
> + valid = 1;
> + }
> + dput(newdent);
> +
> +end_advance:
> + if (!valid)
> + ctl.valid = 0;
> + if (!ctl.filled && (ctl.fpos == filp->f_pos)) {
> + if (!ino)
> + ino = find_inode_number(dentry, qname);
> + if (!ino)
> + ino = iunique(inode->i_sb, 2);
> + ctl.filled = filldir(dirent, qname->name, qname->len,
> + filp->f_pos, ino, DT_UNKNOWN);
> + if (!ctl.filled)
> + filp->f_pos += 1;
> + }
> + ctl.fpos += 1;
> + ctl.idx += 1;
> + *ctrl = ctl;
> + return ctl.valid || !ctl.filled;
> +}
> diff --git a/fs/vmfs/dir.c b/fs/vmfs/dir.c
> new file mode 100644
> index 0000000..cde4a5e
> --- /dev/null
> +++ b/fs/vmfs/dir.c
> @@ -0,0 +1,626 @@
> +/*
> + * dir.c
> + *
> + * Copyright (C) 1995, 1996 by Paal-Kr. Engstad and Volker Lendecke
> + * Copyright (C) 1997 by Volker Lendecke
> + *
> + * Copyright (C) 2008-2009 ARM Limited
> + *
> + * Please add a note about your changes to vmfs_ in the ChangeLog file.
> + */
> +
> +#include <linux/time.h>
> +#include <linux/errno.h>
> +#include <linux/kernel.h>
> +#include <linux/ctype.h>
> +#include <linux/net.h>
> +#include <linux/sched.h>
> +#include <linux/version.h>
> +
> +#include "vmfs_fs.h"
> +#include "vmfs_mount.h"
> +#include "vmfsno.h"
> +
> +#include "vmfs_debug.h"
> +#include "proto.h"
> +
> +static int vmfs_readdir(struct file *, void *, filldir_t);
> +static int vmfs_dir_open(struct inode *, struct file *);
> +
> +static struct dentry *vmfs_lookup(struct inode *, struct dentry *,
> + struct nameidata *);
> +static int vmfs_create(struct inode *, struct dentry *, int,
> + struct nameidata *);
> +static int vmfs_mkdir(struct inode *, struct dentry *, int);
> +static int vmfs_rmdir(struct inode *, struct dentry *);
> +static int vmfs_unlink(struct inode *, struct dentry *);
> +static int vmfs_rename(struct inode *, struct dentry *,
> + struct inode *, struct dentry *);
> +static int vmfs_make_node(struct inode *, struct dentry *, int, dev_t);
> +static int vmfs_link(struct dentry *, struct inode *, struct dentry *);
> +
> +const struct file_operations vmfs_dir_operations = {
> + .read = generic_read_dir,
> + .readdir = vmfs_readdir,
> + .unlocked_ioctl = vmfs_unlocked_ioctl,
> + .open = vmfs_dir_open,
> +};
> +
> +const struct inode_operations vmfs_dir_inode_operations = {
> + .create = vmfs_create,
> + .lookup = vmfs_lookup,
> + .unlink = vmfs_unlink,
> + .mkdir = vmfs_mkdir,
> + .rmdir = vmfs_rmdir,
> + .rename = vmfs_rename,
> + .getattr = vmfs_getattr,
> + .setattr = vmfs_notify_change,
> +};
> +
> +const struct inode_operations vmfs_dir_inode_operations_unix = {
> + .create = vmfs_create,
> + .lookup = vmfs_lookup,
> + .unlink = vmfs_unlink,
> + .mkdir = vmfs_mkdir,
> + .rmdir = vmfs_rmdir,
> + .rename = vmfs_rename,
> + .getattr = vmfs_getattr,
> + .setattr = vmfs_notify_change,
> + .symlink = vmfs_symlink,
> + .mknod = vmfs_make_node,
> + .link = vmfs_link,
> +};
> +
> +/*
> + * Read a directory, using filldir to fill the dirent memory.
> + * vmfs_proc_readdir does the actual reading from the vmfs server.
> + *
> + * The cache code is almost directly taken from ncpfs
> + */
> +static int vmfs_readdir(struct file *filp, void *dirent, filldir_t filldir)
> +{
> + struct dentry *dentry = filp->f_path.dentry;
> + struct inode *dir = dentry->d_inode;
> + struct vmfs_sb_info *server = server_from_dentry(dentry);
> + union vmfs_dir_cache *cache = NULL;
> + struct vmfs_cache_control ctl;
> + struct page *page = NULL;
> + int result;
> +
> + ctl.page = NULL;
> + ctl.cache = NULL;
> +
> + VERBOSE("reading %s/%s, f_pos=%d\n",
> + DENTRY_PATH(dentry), (int)filp->f_pos);
> +
> + result = 0;
> +
> + mutex_lock(&vmfs_mutex);
> +
> + switch ((unsigned int)filp->f_pos) {
> + case 0:
> + if (filldir(dirent, ".", 1, 0, dir->i_ino, DT_DIR) < 0)
> + goto out;
> + filp->f_pos = 1;
> + /* fallthrough */
> + case 1:
> + if (filldir(dirent, "..", 2, 1, parent_ino(dentry), DT_DIR) < 0)
> + goto out;
> + filp->f_pos = 2;
> + }
> +
> + /*
> + * Make sure our inode is up-to-date.
> + */
> + result = vmfs_revalidate_inode(dentry);
> + if (result)
> + goto out;
> +
> + page = grab_cache_page(&dir->i_data, 0);
> + if (!page)
> + goto read_really;
> +
> + ctl.cache = cache = kmap(page);
> + ctl.head = cache->head;
> +
> + if (!PageUptodate(page) || !ctl.head.eof) {
> + VERBOSE("%s/%s, page uptodate=%d, eof=%d\n",
> + DENTRY_PATH(dentry), PageUptodate(page), ctl.head.eof);
> + goto init_cache;
> + }
> +
> + if (filp->f_pos == 2) {
> + if (jiffies - ctl.head.time >= VMFS_MAX_AGE(server))
> + goto init_cache;
> +
> + /*
> + * N.B. ncpfs checks mtime of dentry too here, we don't.
> + * 1. common vmfs servers do not update mtime on dir changes
> + * 2. it requires an extra vmfs request
> + * (revalidate has the same timeout as ctl.head.time)
> + *
> + * Instead vmfs_ invalidates its own cache on local changes
> + * and remote changes are not seen until timeout.
> + */
> + }
> +
> + if (filp->f_pos > ctl.head.end)
> + goto finished;
> +
> + ctl.fpos = filp->f_pos + (VMFS_DIRCACHE_START - 2);
> + ctl.ofs = ctl.fpos / VMFS_DIRCACHE_SIZE;
> + ctl.idx = ctl.fpos % VMFS_DIRCACHE_SIZE;
> +
> + for (;;) {
> + if (ctl.ofs != 0) {
> + ctl.page = find_lock_page(&dir->i_data, ctl.ofs);
> + if (!ctl.page)
> + goto invalid_cache;
> + ctl.cache = kmap(ctl.page);
> + if (!PageUptodate(ctl.page))
> + goto invalid_cache;
> + }
> + while (ctl.idx < VMFS_DIRCACHE_SIZE) {
> + struct dentry *dent;
> + int res;
> +
> + dent = vmfs_dget_fpos(ctl.cache->dentry[ctl.idx],
> + dentry, filp->f_pos);
> + if (!dent)
> + goto invalid_cache;
> +
> + res = filldir(dirent, dent->d_name.name,
> + dent->d_name.len, filp->f_pos,
> + dent->d_inode->i_ino, DT_UNKNOWN);
> + dput(dent);
> + if (res)
> + goto finished;
> + filp->f_pos += 1;
> + ctl.idx += 1;
> + if (filp->f_pos > ctl.head.end)
> + goto finished;
> + }
> + if (ctl.page) {
> + kunmap(ctl.page);
> + SetPageUptodate(ctl.page);
> + unlock_page(ctl.page);
> + page_cache_release(ctl.page);
> + ctl.page = NULL;
> + }
> + ctl.idx = 0;
> + ctl.ofs += 1;
> + }
> +invalid_cache:
> + if (ctl.page) {
> + kunmap(ctl.page);
> + unlock_page(ctl.page);
> + page_cache_release(ctl.page);
> + ctl.page = NULL;
> + }
> + ctl.cache = cache;
> +init_cache:
> + vmfs_invalidate_dircache_entries(dentry);
> + ctl.head.time = jiffies;
> + ctl.head.eof = 0;
> + ctl.fpos = 2;
> + ctl.ofs = 0;
> + ctl.idx = VMFS_DIRCACHE_START;
> + ctl.filled = 0;
> + ctl.valid = 1;
> +read_really:
> + result = server->ops->readdir(filp, dirent, filldir, &ctl);
> + if (result == -ERESTARTSYS && page)
> + ClearPageUptodate(page);
> + if (ctl.idx == -1)
> + goto invalid_cache; /* retry */
> + ctl.head.end = ctl.fpos - 1;
> + ctl.head.eof = ctl.valid;
> +finished:
> + if (page) {
> + cache->head = ctl.head;
> + kunmap(page);
> + if (result != -ERESTARTSYS)
> + SetPageUptodate(page);
> + unlock_page(page);
> + page_cache_release(page);
> + }
> + if (ctl.page) {
> + kunmap(ctl.page);
> + SetPageUptodate(ctl.page);
> + unlock_page(ctl.page);
> + page_cache_release(ctl.page);
> + }
> +out:
> + mutex_unlock(&vmfs_mutex);
> + return result;
> +}
> +
> +static int vmfs_dir_open(struct inode *dir, struct file *file)
> +{
> + struct dentry *dentry = file->f_path.dentry;
> + int error = 0;
> +
> + VERBOSE("(%s/%s)\n", dentry->d_parent->d_name.name,
> + file->f_path.dentry->d_name.name);
> +
> + mutex_lock(&vmfs_mutex);
> +
> +
> + if (!IS_ROOT(dentry))
> + error = vmfs_revalidate_inode(dentry);
> +
> + mutex_unlock(&vmfs_mutex);
> + return error;
> +}
> +
> +/*
> + * Dentry operations routines
> + */
> +static int vmfs_lookup_validate(struct dentry *, struct nameidata *);
> +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 38)
> +static int vmfs_delete_dentry(struct dentry *);
> +#else
> +static int vmfs_delete_dentry(const struct dentry *);
> +#endif
> +
> +
> +static struct dentry_operations vmfs__dentry_operations_case = {
> + .d_revalidate = vmfs_lookup_validate,
> + .d_delete = vmfs_delete_dentry,
> +};
> +
> +/*
> + * This is the callback when the dcache has a lookup hit.
> + */
> +static int vmfs_lookup_validate(struct dentry *dentry, struct nameidata *nd)
> +{
> + struct vmfs_sb_info *server = server_from_dentry(dentry);
> + struct inode *inode = dentry->d_inode;
> + unsigned long age = jiffies - dentry->d_time;
> + int valid;
> +
> + /*
> + * The default validation is based on dentry age:
> + * we believe in dentries for a few seconds. (But each
> + * successful server lookup renews the timestamp.)
> + */
> + valid = (age <= VMFS_MAX_AGE(server));
> +#ifdef VMFSFS_DEBUG_VERBOSE
> + if (!valid)
> + VERBOSE("%s/%s not valid, age=%lu\n", DENTRY_PATH(dentry), age);
> +#endif
> +
> + if (inode) {
> + mutex_lock(&vmfs_mutex);
> + if (is_bad_inode(inode)) {
> + PARANOIA("%s/%s has dud inode\n", DENTRY_PATH(dentry));
> + valid = 0;
> + } else if (!valid)
> + valid = (vmfs_revalidate_inode(dentry) == 0);
> + mutex_unlock(&vmfs_mutex);
> + } else {
> + /*
> + * What should we do for negative dentries?
> + */
> + }
> + return valid;
> +}
> +
> +
> +/*
> + * This is the callback from dput() when d_count is going to 0.
> + * We use this to unhash dentries with bad inodes.
> + */
> +static int
> +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 38)
> +vmfs_delete_dentry(struct dentry *dentry)
> +#else
> +vmfs_delete_dentry(const struct dentry *dentry)
> +#endif
> +{
> + if (dentry->d_inode) {
> + if (is_bad_inode(dentry->d_inode)) {
> + PARANOIA("bad inode, unhashing %s/%s\n",
> + DENTRY_PATH(dentry));
> + return 1;
> + }
> + } else {
> + /* N.B. Unhash negative dentries? */
> + }
> + return 0;
> +}
> +
> +/*
> + * Initialize a new dentry
> + */
> +void vmfs_new_dentry(struct dentry *dentry)
> +{
> + dentry->d_op = &vmfs__dentry_operations_case;
> +}
> +
> +/*
> + * Whenever a lookup succeeds, we know the parent directories
> + * are all valid, so we want to update the dentry timestamps.
> + * N.B. Move this to dcache?
> + */
> +void vmfs_renew_times(struct dentry *dentry)
> +{
> + dget(dentry);
> +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 37)
> + spin_lock(&dentry->d_lock);
> + for (;;) {
> + struct dentry *parent;
> +
> + dentry->d_time = jiffies;
> + if (IS_ROOT(dentry))
> + break;
> + parent = dentry->d_parent;
> + dget(parent);
> + spin_unlock(&dentry->d_lock);
> + dput(dentry);
> + dentry = parent;
> + spin_lock(&dentry->d_lock);
> + }
> + spin_unlock(&dentry->d_lock);
> +#else
> + dentry->d_time = jiffies;
> +
> + while (!IS_ROOT(dentry)) {
> + struct dentry *parent = dget_parent(dentry);
> + dput(dentry);
> + dentry = parent;
> +
> + dentry->d_time = jiffies;
> + }
> +#endif
> + dput(dentry);
> +}
> +
> +static struct dentry *vmfs_lookup(struct inode *dir, struct dentry *dentry,
> + struct nameidata *nd)
> +{
> + struct vmfs_fattr finfo;
> + struct inode *inode;
> + int error;
> + struct vmfs_sb_info *server;
> +
> + VERBOSE("%s\n", dentry->d_name.name);
> +
> + error = -ENAMETOOLONG;
> + if (dentry->d_name.len > VMFS_MAXNAMELEN)
> + goto out;
> +
> + /* Do not allow lookup of names with backslashes in */
> + error = -EINVAL;
> +#if 0
> + if (memchr(dentry->d_name.name, '\\', dentry->d_name.len))
> + goto out;
> +#endif
> +
> + mutex_lock(&vmfs_mutex);
> + error = vmfs_proc_getattr(dentry, &finfo);
> +#ifdef VMFSFS_PARANOIA
> + if (error && error != -ENOENT)
> + PARANOIA("find %s/%s failed, error=%d\n",
> + DENTRY_PATH(dentry), error);
> +#endif
> +
> + inode = NULL;
> + if (error == -ENOENT)
> + goto add_entry;
> + if (!error) {
> + error = -EACCES;
> + finfo.f_ino = iunique(dentry->d_sb, 2);
> + inode = vmfs_iget(dir->i_sb, &finfo);
> + if (inode) {
> +add_entry:
> + server = server_from_dentry(dentry);
> + dentry->d_op = &vmfs__dentry_operations_case;
> + d_add(dentry, inode);
> + vmfs_renew_times(dentry);
> + error = 0;
> + }
> + }
> + mutex_unlock(&vmfs_mutex);
> +out:
> + return ERR_PTR(error);
> +}
> +
> +/*
> + * This code is common to all routines creating a new inode.
> + */
> +static int vmfs_instantiate(struct dentry *dentry, int32_t vhandle,
> + int have_id)
> +{
> + struct inode *inode;
> + int error;
> + struct vmfs_fattr fattr;
> +
> + VERBOSE("file %s/%s, fileid=%u\n", DENTRY_PATH(dentry), vhandle);
> +
> + error = vmfs_proc_getattr(dentry, &fattr);
> + if (error)
> + goto out_close;
> +
> + vmfs_renew_times(dentry);
> + fattr.f_ino = iunique(dentry->d_sb, 2);
> + inode = vmfs_iget(dentry->d_sb, &fattr);
> + if (!inode)
> + goto out_no_inode;
> +
> + if (have_id) {
> + /* this is really only for create, where there is a
> + * catch-22 between creating the file and inode */
> + struct vmfs_inode_info *ei = VMFS_I(inode);
> + ei->vhandle = vhandle;
> + ei->vopen = 1;
> + ei->vaccess = VFS_OPEN_RDWR;
> + }
> + d_instantiate(dentry, inode);
> +out:
> + return error;
> +
> +out_no_inode:
> + error = -EACCES;
> +out_close:
> + if (have_id) {
> + PARANOIA("%s/%s failed, error=%d, closing %u\n",
> + DENTRY_PATH(dentry), error, vhandle);
> + vmfs_close_fileid(dentry, vhandle);
> + }
> + goto out;
> +}
> +
> +/* N.B. How should the mode argument be used? */
> +static int
> +vmfs_create(struct inode *dir, struct dentry *dentry, int mode,
> + struct nameidata *nd)
> +{
> + int32_t fileid;
> + int error;
> +
> + VERBOSE("creating %s/%s, mode=%d\n", DENTRY_PATH(dentry), mode);
> +
> + mutex_lock(&vmfs_mutex);
> +
> + vmfs_invalid_dir_cache(dir);
> + error = vmfs_proc_create(dentry, mode, &fileid);
> + if (!error) {
> + error = vmfs_instantiate(dentry, fileid, 1);
> + } else {
> + PARANOIA("%s/%s failed, error=%d\n",
> + DENTRY_PATH(dentry), error);
> + }
> + mutex_unlock(&vmfs_mutex);
> + return error;
> +}
> +
> +/* N.B. How should the mode argument be used? */
> +static int vmfs_mkdir(struct inode *dir, struct dentry *dentry, int mode)
> +{
> + int error;
> +
> + VERBOSE("\n");
> +
> + mutex_lock(&vmfs_mutex);
> + vmfs_invalid_dir_cache(dir);
> + error = vmfs_proc_mkdir(dentry);
> + if (!error)
> + error = vmfs_instantiate(dentry, 0, 0);
> + mutex_unlock(&vmfs_mutex);
> + return error;
> +}
> +
> +static int vmfs_rmdir(struct inode *dir, struct dentry *dentry)
> +{
> + struct inode *inode = dentry->d_inode;
> + int error;
> +
> + VERBOSE("\n");
> + /*
> + * Close the directory if it's open.
> + */
> + mutex_lock(&vmfs_mutex);
> + vmfs_close(inode);
> +
> + /*
> + * Check that nobody else is using the directory..
> + */
> + error = -EBUSY;
> + if (!d_unhashed(dentry))
> + goto out;
> +
> + vmfs_invalid_dir_cache(dir);
> + error = vmfs_proc_rmdir(dentry);
> +
> +out:
> + mutex_unlock(&vmfs_mutex);
> + return error;
> +}
> +
> +static int vmfs_unlink(struct inode *dir, struct dentry *dentry)
> +{
> + int error;
> +
> + /*
> + * Close the file if it's open.
> + */
> + mutex_lock(&vmfs_mutex);
> + vmfs_close(dentry->d_inode);
> +
> + vmfs_invalid_dir_cache(dir);
> + error = vmfs_proc_unlink(dentry);
> + if (!error)
> + vmfs_renew_times(dentry);
> + mutex_unlock(&vmfs_mutex);
> + return error;
> +}
> +
> +static int
> +vmfs_rename(struct inode *old_dir, struct dentry *old_dentry,
> + struct inode *new_dir, struct dentry *new_dentry)
> +{
> + int error;
> +
> + VERBOSE("\n");
> +
> + /*
> + * Close any open files, and check whether to delete the
> + * target before attempting the rename.
> + */
> + mutex_lock(&vmfs_mutex);
> + if (old_dentry->d_inode)
> + vmfs_close(old_dentry->d_inode);
> + if (new_dentry->d_inode) {
> + vmfs_close(new_dentry->d_inode);
> + error = vmfs_proc_unlink(new_dentry);
> + if (error) {
> + VERBOSE("unlink %s/%s, error=%d\n",
> + DENTRY_PATH(new_dentry), error);
> + goto out;
> + }
> + /* FIXME */
> + d_delete(new_dentry);
> + }
> +
> + vmfs_invalid_dir_cache(old_dir);
> + vmfs_invalid_dir_cache(new_dir);
> + error = vmfs_proc_mv(old_dentry, new_dentry);
> + if (!error) {
> + vmfs_renew_times(old_dentry);
> + vmfs_renew_times(new_dentry);
> + }
> +out:
> + mutex_unlock(&vmfs_mutex);
> + return error;
> +}
> +
> +/*
> + * FIXME: samba servers won't let you create device nodes unless uid/gid
> + * matches the connection credentials (and we don't know which those are ...)
> + */
> +static int
> +vmfs_make_node(struct inode *dir, struct dentry *dentry, int mode, dev_t dev)
> +{
> + return -EINVAL;
> +}
> +
> +/*
> + * dentry = existing file
> + * new_dentry = new file
> + */
> +static int
> +vmfs_link(struct dentry *dentry, struct inode *dir, struct dentry *new_dentry)
> +{
> + int error;
> +
> + DEBUG1("vmfs_link old=%s/%s new=%s/%s\n",
> + DENTRY_PATH(dentry), DENTRY_PATH(new_dentry));
> + vmfs_invalid_dir_cache(dir);
> + error = vmfs_proc_link(server_from_dentry(dentry), dentry, new_dentry);
> + if (!error) {
> + vmfs_renew_times(dentry);
> + error = vmfs_instantiate(new_dentry, 0, 0);
> + }
> + return error;
> +}
> diff --git a/fs/vmfs/file.c b/fs/vmfs/file.c
> new file mode 100644
> index 0000000..833e7a7
> --- /dev/null
> +++ b/fs/vmfs/file.c
> @@ -0,0 +1,500 @@
> +/*
> + * file.c
> + *
> + * Copyright (C) 1995, 1996, 1997 by Paal-Kr. Engstad and Volker Lendecke
> + * Copyright (C) 1997 by Volker Lendecke
> + *
> + * Please add a note about your changes to vmfs_ in the ChangeLog file.
> + */
> +
> +#include <linux/time.h>
> +#include <linux/kernel.h>
> +#include <linux/errno.h>
> +#include <linux/fcntl.h>
> +#include <linux/stat.h>
> +#include <linux/mm.h>
> +#include <linux/slab.h>
> +#include <linux/pagemap.h>
> +#include <linux/net.h>
> +#include <linux/aio.h>
> +
> +#include <asm/uaccess.h>
> +#include <asm/system.h>
> +#include <linux/version.h>
> +
> +#include "vmfsno.h"
> +#include "vmfs_fs.h"
> +
> +#include "vmfs_debug.h"
> +#include "proto.h"
> +
> +static int
> +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 35)
> +vmfs_fsync(struct file *file, struct dentry *dentry, int datasync)
> +{
> +#else
> +vmfs_fsync(struct file *file, int datasync)
> +{
> + struct dentry *dentry = file->f_path.dentry;
> +#endif
> + struct vmfs_sb_info *server = server_from_dentry(dentry);
> + int result;
> +
> + VERBOSE("sync file %s/%s\n", DENTRY_PATH(dentry));
> +
> + /*
> + * The VFS will writepage() all dirty pages for us, but we
> + * should send a VMFSflush to the server, letting it know that
> + * we want things synchronized with actual storage.
> + *
> + * Note: this function requires all pages to have been written already
> + * (should be ok with writepage_sync)
> + */
> + mutex_lock(&vmfs_mutex);
> + result = vmfs_proc_flush(server, VMFS_I(dentry->d_inode)->vhandle);
> + mutex_unlock(&vmfs_mutex);
> +
> + return result;
> +}
> +
> +/*
> + * Read a page synchronously.
> + */
> +static int vmfs_readpage_sync(struct dentry *dentry, struct page *page)
> +{
> + char *buffer = kmap(page);
> + loff_t offset = (loff_t) page->index << PAGE_CACHE_SHIFT;
> + struct vmfs_sb_info *server = server_from_dentry(dentry);
> + int count = PAGE_SIZE;
> + unsigned int rsize = count;
> + int result;
> +
> + VERBOSE("file %s/%s, count=%d@%lld, rsize=%d\n",
> + DENTRY_PATH(dentry), count, offset, rsize);
> +
> + result = vmfs_open(dentry, 0, VMFS_O_RDONLY);
> + if (result < 0)
> + goto io_error;
> +
> + do {
> + if (count < rsize)
> + rsize = count;
> +
> + result =
> + server->ops->read(dentry->d_inode, offset, rsize, buffer);
> + if (result < 0)
> + goto io_error;
> +
> + count -= result;
> + offset += result;
> + buffer += result;
> + dentry->d_inode->i_atime =
> + current_fs_time(dentry->d_inode->i_sb);
> + if (result < rsize)
> + break;
> + } while (count);
> +
> + memset(buffer, 0, count);
> + flush_dcache_page(page);
> + SetPageUptodate(page);
> + result = 0;
> +
> +io_error:
> + kunmap(page);
> + unlock_page(page);
> + return result;
> +}
> +
> +/*
> + * We are called with the page locked and we unlock it when done.
> + */
> +static int vmfs_readpage(struct file *file, struct page *page)
> +{
> + int error;
> + struct dentry *dentry = file->f_path.dentry;
> +
> + page_cache_get(page);
> + error = vmfs_readpage_sync(dentry, page);
> + page_cache_release(page);
> + return error;
> +}
> +
> +/*
> + * Write a page synchronously.
> + * Offset is the data offset within the page.
> + */
> +static int
> +vmfs_writepage_sync(struct inode *inode, struct page *page,
> + unsigned long pageoffset, unsigned int count)
> +{
> + loff_t offset;
> + char *buffer = kmap(page) + pageoffset;
> + struct vmfs_sb_info *server = server_from_inode(inode);
> + unsigned int wsize = count;
> + int ret = 0;
> +
> + offset = ((loff_t) page->index << PAGE_CACHE_SHIFT) + pageoffset;
> + VERBOSE("file ino=%ld, handle=%d, count=%d@%lld, wsize=%d\n",
> + inode->i_ino, VMFS_I(inode)->vhandle, count, offset, wsize);
> +
> + do {
> + int write_ret;
> +
> + if (count < wsize)
> + wsize = count;
> +
> + write_ret = server->ops->write(inode, offset, wsize, buffer);
> + if (write_ret < 0) {
> + PARANOIA("failed write, wsize=%d, write_ret=%d\n",
> + wsize, write_ret);
> + ret = write_ret;
> + break;
> + }
> +
> + /* N.B. what if result < wsize?? */
> +#ifdef VMFSFS_PARANOIA
> + if (write_ret < wsize)
> + PARANOIA("short write, wsize=%d, write_ret=%d\n",
> + wsize, write_ret);
> +#endif
> + buffer += wsize;
> + offset += wsize;
> + count -= wsize;
> + /*
> + * Update the inode now rather than waiting for a refresh.
> + */
> +
> + inode->i_mtime = inode->i_atime = current_fs_time(inode->i_sb);
> + if (offset > inode->i_size)
> + inode->i_size = offset;
> + } while (count);
> +
> + kunmap(page);
> + return ret;
> +}
> +
> +/*
> + * Write a page to the server. This will be used for NFS swapping only
> + * (for now), and we currently do this synchronously only.
> + *
> + * We are called with the page locked and we unlock it when done.
> + */
> +static int vmfs_writepage(struct page *page, struct writeback_control *wbc)
> +{
> + struct address_space *mapping = page->mapping;
> + struct inode *inode;
> + unsigned long end_index;
> + unsigned offset = PAGE_CACHE_SIZE;
> + int err;
> +
> + DEBUG1("\n");
> +
> + BUG_ON(!mapping);
> + inode = mapping->host;
> + BUG_ON(!inode);
> +
> + end_index = inode->i_size >> PAGE_CACHE_SHIFT;
> +
> + /* easy case */
> + if (page->index < end_index)
> + goto do_it;
> + /* things got complicated... */
> + offset = inode->i_size & (PAGE_CACHE_SIZE - 1);
> + /* OK, are we completely out? */
> + if (page->index >= end_index + 1 || !offset)
> + return 0; /* truncated - don't care */
> +do_it:
> + page_cache_get(page);
> + err = vmfs_writepage_sync(inode, page, 0, offset);
> + SetPageUptodate(page);
> + unlock_page(page);
> + page_cache_release(page);
> + return err;
> +}
> +
> +static int
> +vmfs_updatepage(struct file *file, struct page *page, unsigned long offset,
> + unsigned int count)
> +{
> + struct dentry *dentry = file->f_path.dentry;
> +
> + DEBUG1("(%s/%s %d@%lld)\n", DENTRY_PATH(dentry), count,
> + ((unsigned long long)page->index << PAGE_CACHE_SHIFT) + offset);
> +
> + return vmfs_writepage_sync(dentry->d_inode, page, offset, count);
> +}
> +
> +static ssize_t
> +vmfs_file_aio_read(struct kiocb *iocb, const struct iovec *iov,
> + unsigned long nr_segs, loff_t pos)
> +{
> + struct file *file = iocb->ki_filp;
> + struct dentry *dentry = file->f_path.dentry;
> + ssize_t status;
> +
> + VERBOSE("file %s/%s, count=%lu@%lu\n", DENTRY_PATH(dentry),
> + (unsigned long)iocb->ki_left, (unsigned long)pos);
> +
> + mutex_lock(&vmfs_mutex);
> + status = vmfs_revalidate_inode(dentry);
> + mutex_unlock(&vmfs_mutex);
> + if (status) {
> + PARANOIA("%s/%s validation failed, error=%Zd\n",
> + DENTRY_PATH(dentry), status);
> + goto out;
> + }
> +
> + VERBOSE("before read, size=%ld, flags=%x, atime=%ld\n",
> + (long)dentry->d_inode->i_size,
> + dentry->d_inode->i_flags, dentry->d_inode->i_atime.tv_sec);
> +
> + status = generic_file_aio_read(iocb, iov, nr_segs, pos);
> +out:
> + return status;
> +}
> +
> +static int vmfs_file_mmap(struct file *file, struct vm_area_struct *vma)
> +{
> + struct dentry *dentry = file->f_path.dentry;
> + int status;
> +
> + VERBOSE("file %s/%s, address %lu - %lu\n",
> + DENTRY_PATH(dentry), vma->vm_start, vma->vm_end);
> +
> + mutex_lock(&vmfs_mutex);
> + status = vmfs_revalidate_inode(dentry);
> + mutex_unlock(&vmfs_mutex);
> + if (status) {
> + PARANOIA("%s/%s validation failed, error=%d\n",
> + DENTRY_PATH(dentry), status);
> + goto out;
> + }
> + status = generic_file_mmap(file, vma);
> +out:
> + return status;
> +}
> +
> +static ssize_t
> +vmfs_file_splice_read(struct file *file, loff_t *ppos,
> + struct pipe_inode_info *pipe, size_t count,
> + unsigned int flags)
> +{
> + struct dentry *dentry = file->f_path.dentry;
> + ssize_t status;
> +
> + VERBOSE("file %s/%s, pos=%lld, count=%u\n",
> + DENTRY_PATH(dentry), *ppos, count);
> +
> + mutex_lock(&vmfs_mutex);
> + status = vmfs_revalidate_inode(dentry);
> + mutex_unlock(&vmfs_mutex);
> + if (status) {
> + PARANOIA("%s/%s validation failed, error=%Zd\n",
> + DENTRY_PATH(dentry), status);
> + goto out;
> + }
> + status = generic_file_splice_read(file, ppos, pipe, count, flags);
> +out:
> + return status;
> +}
> +
> +/*
> + * This does the "real" work of the write. The generic routine has
> + * allocated the page, locked it, done all the page alignment stuff
> + * calculations etc. Now we should just copy the data from user
> + * space and write it back to the real medium..
> + *
> + * If the writer ends up delaying the write, the writer needs to
> + * increment the page use counts until he is done with the page.
> + */
> +static int vmfs_write_begin(struct file *file, struct address_space *mapping,
> + loff_t pos, unsigned len, unsigned flags,
> + struct page **pagep, void **fsdata)
> +{
> + pgoff_t index = pos >> PAGE_CACHE_SHIFT;
> + *pagep = grab_cache_page(mapping, index);
> + if (!*pagep)
> + return -ENOMEM;
> + return 0;
> +}
> +
> +static int vmfs_write_end(struct file *file, struct address_space *mapping,
> + loff_t pos, unsigned len, unsigned copied,
> + struct page *page, void *fsdata)
> +{
> + int status;
> + unsigned offset = pos & (PAGE_CACHE_SIZE - 1);
> +
> + mutex_lock(&vmfs_mutex);
> + status = vmfs_updatepage(file, page, offset, copied);
> + mutex_unlock(&vmfs_mutex);
> +
> + if (!status) {
> + if (!PageUptodate(page) && copied == PAGE_CACHE_SIZE)
> + SetPageUptodate(page);
> + status = copied;
> + }
> +
> + unlock_page(page);
> + page_cache_release(page);
> +
> + return status;
> +}
> +
> +const struct address_space_operations vmfs_file_aops = {
> + .readpage = vmfs_readpage,
> + .writepage = vmfs_writepage,
> + .write_begin = vmfs_write_begin,
> + .write_end = vmfs_write_end,
> +};
> +
> +/*
> + * Write to a file (through the page cache).
> + */
> +static ssize_t
> +vmfs_file_aio_write(struct kiocb *iocb, const struct iovec *iov,
> + unsigned long nr_segs, loff_t pos)
> +{
> + struct file *file = iocb->ki_filp;
> + struct dentry *dentry = file->f_path.dentry;
> + ssize_t result;
> +
> + VERBOSE("file %s/%s, count=%lu@%lu\n",
> + DENTRY_PATH(dentry),
> + (unsigned long)iocb->ki_left, (unsigned long)pos);
> +
> + mutex_lock(&vmfs_mutex);
> + result = vmfs_revalidate_inode(dentry);
> + mutex_unlock(&vmfs_mutex);
> + if (result) {
> + PARANOIA("%s/%s validation failed, error=%Zd\n",
> + DENTRY_PATH(dentry), result);
> + goto out;
> + }
> +
> + mutex_lock(&vmfs_mutex);
> + result = vmfs_open(dentry, 0, VMFS_O_WRONLY);
> + mutex_unlock(&vmfs_mutex);
> +
> + DEBUG1("1\n");
> +
> + if (result)
> + goto out;
> +
> + if (iocb->ki_left > 0) {
> + DEBUG1("1\n");
> +
> + result = generic_file_aio_write(iocb, iov, nr_segs, pos);
> + VERBOSE("pos=%ld, size=%ld, mtime=%ld, atime=%ld\n",
> + (long)file->f_pos, (long)dentry->d_inode->i_size,
> + dentry->d_inode->i_mtime.tv_sec,
> + dentry->d_inode->i_atime.tv_sec);
> +
> + DEBUG1("2\n");
> + }
> +out:
> + DEBUG1("return\n");
> + return result;
> +}
> +
> +static int vmfs_file_open(struct inode *inode, struct file *file)
> +{
> + int result;
> + struct dentry *dentry = file->f_path.dentry;
> + int vmfs_mode = (file->f_mode & O_ACCMODE) - 1;
> + int vmfs_flags = file->f_flags;
> +
> + VERBOSE("\n");
> +
> + mutex_lock(&vmfs_mutex);
> + result = vmfs_open(dentry, vmfs_flags, vmfs_mode);
> + if (result)
> + goto out;
> +
> + DEBUG1("inode=%p, ei=%p\n", inode, VMFS_I(inode));
> +
> + VMFS_I(inode)->openers++;
> +out:
> + mutex_unlock(&vmfs_mutex);
> + DEBUG1("return\n");
> +
> + return result;
> +}
> +
> +static int vmfs_file_release(struct inode *inode, struct file *file)
> +{
> + mutex_lock(&vmfs_mutex);
> + if (!--VMFS_I(inode)->openers) {
> + /* We must flush any dirty pages now as we won't be able to
> + write anything after close. mmap can trigger this.
> + "openers" should perhaps include mmap'ers ... */
> + filemap_write_and_wait(inode->i_mapping);
> + vmfs_close(inode);
> + }
> + mutex_unlock(&vmfs_mutex);
> + return 0;
> +}
> +
> +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 28)
> +static loff_t vmfs_remote_llseek(struct file *file, loff_t offset, int origin)
> +{
> + loff_t ret;
> + mutex_lock(&vmfs_mutex);
> + ret = generic_file_llseek(file, offset, origin);
> + mutex_unlock(&vmfs_mutex);
> + return ret;
> +}
> +#endif
> +/*
> + * Check whether the required access is compatible with
> + * an inode's permission. VMFS doesn't recognize superuser
> + * privileges, so we need our own check for this.
> + */
> +static int
> +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 28)
> +vmfs_file_permission(struct inode *inode, int mask, struct nameidata *nd)
> +#elif LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 38)
> +vmfs_file_permission(struct inode *inode, int mask)
> +#else
> +vmfs_file_permission(struct inode *inode, int mask, unsigned int flags)
> +#endif
> +{
> + int mode = inode->i_mode;
> + int error = 0;
> +
> + VERBOSE("mode=%x, mask=%x\n", mode, mask);
> +
> + /* Look at user permissions */
> + mode >>= 6;
> +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 28)
> + if ((mask & ~mode) & (MAY_READ | MAY_WRITE | MAY_EXEC))
> +#else
> + if ((mode & 7 & mask) != mask)
> +#endif
> + error = -EACCES;
> + return error;
> +}
> +
> +const struct file_operations vmfs_file_operations = {
> +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 28)
> + .llseek = vmfs_remote_llseek,
> +#else
> + .llseek = remote_llseek,
> +#endif
> + .read = do_sync_read,
> + .aio_read = vmfs_file_aio_read,
> + .write = do_sync_write,
> + .aio_write = vmfs_file_aio_write,
> + .unlocked_ioctl = vmfs_unlocked_ioctl,
> + .mmap = vmfs_file_mmap,
> + .open = vmfs_file_open,
> + .release = vmfs_file_release,
> + .fsync = vmfs_fsync,
> + .splice_read = vmfs_file_splice_read,
> +};
> +
> +const struct inode_operations vmfs_file_inode_operations = {
> + .permission = vmfs_file_permission,
> + .getattr = vmfs_getattr,
> + .setattr = vmfs_notify_change,
> +};
> diff --git a/fs/vmfs/getopt.c b/fs/vmfs/getopt.c
> new file mode 100644
> index 0000000..d5a76c8
> --- /dev/null
> +++ b/fs/vmfs/getopt.c
> @@ -0,0 +1,67 @@
> +/*
> + * getopt.c
> + */
> +
> +#include <linux/kernel.h>
> +#include <linux/string.h>
> +#include <linux/net.h>
> +
> +#include "getopt.h"
> +
> +/**
> + * vmfs_getopt - option parser
> + * @caller: name of the caller, for error messages
> + * @options: the options string
> + * @opts: an array of &struct option entries controlling parser operations
> + * @optopt: output; will contain the current option
> + * @optarg: output; will contain the value (if one exists)
> + * @flag: output; may be NULL; should point to a long for or'ing flags
> + * @value: output; may be NULL; will be overwritten with the integer value
> + * of the current argument.
> + *
> + * Helper to parse options on the format used by mount ("a=b,c=d,e,f").
> + * Returns opts->val if a matching entry in the 'opts' array is found,
> + * 0 when no more tokens are found, -1 if an error is encountered.
> + */
> +int vmfs_getopt(char *caller, char **options, struct option *opts,
> + char **optopt, char **optarg, unsigned long *flag,
> + unsigned long *value)
> +{
> + char *token;
> + char *val;
> + int i;
> +
> + do {
> + token = strsep(options, ",");
> + if (token == NULL)
> + return 0;
> + } while (*token == '\0');
> + *optopt = token;
> +
> + *optarg = NULL;
> + val = strchr(token, '=');
> + if (val != NULL) {
> + *val++ = 0;
> + if (value)
> + *value = kstrtoul(val, NULL, 0);
> + *optarg = val;
> + }
> +
> + for (i = 0; opts[i].name != NULL; i++) {
> + if (!strcmp(opts[i].name, token)) {
> + if (!opts[i].flag && (!val || !*val)) {
> + printk
> + ("%s: the %s option requires an argument\n",
> + caller, token);
> + return -1;
> + }
> +
> + if (flag && opts[i].flag)
> + *flag |= opts[i].flag;
> +
> + return opts[i].val;
> + }
> + }
> + printk("%s: Unrecognized mount option %s\n", caller, token);
> + return -1;
> +}
> diff --git a/fs/vmfs/getopt.h b/fs/vmfs/getopt.h
> new file mode 100644
> index 0000000..98dddfc
> --- /dev/null
> +++ b/fs/vmfs/getopt.h
> @@ -0,0 +1,14 @@
> +#ifndef _LINUX_GETOPT_H
> +#define _LINUX_GETOPT_H
> +
> +struct option {
> + const char *name;
> + unsigned long flag;
> + int val;
> +};
> +
> +extern int vmfs_getopt(char *caller, char **options, struct option *opts,
> + char **optopt, char **optarg, unsigned long *flag,
> + unsigned long *value);
> +
> +#endif /* _LINUX_GETOPT_H */
> diff --git a/fs/vmfs/inode.c b/fs/vmfs/inode.c
> new file mode 100644
> index 0000000..2d92cf2
> --- /dev/null
> +++ b/fs/vmfs/inode.c
> @@ -0,0 +1,653 @@
> +/*
> + * inode.c
> + *
> + * Copyright (C) 1995, 1996 by Paal-Kr. Engstad and Volker Lendecke
> + * Copyright (C) 1997 by Volker Lendecke
> + *
> + * Copyright (C) 2008-2009 ARM Limited
> + *
> + * Please add a note about your changes to vmfs_ in the ChangeLog file.
> + */
> +
> +#include <linux/module.h>
> +#include <linux/time.h>
> +#include <linux/kernel.h>
> +#include <linux/mm.h>
> +#include <linux/string.h>
> +#include <linux/stat.h>
> +#include <linux/errno.h>
> +#include <linux/slab.h>
> +#include <linux/init.h>
> +#include <linux/file.h>
> +#include <linux/dcache.h>
> +#include <linux/seq_file.h>
> +#include <linux/mount.h>
> +#include <linux/vfs.h>
> +#include <linux/highuid.h>
> +#include <linux/sched.h>
> +#include <linux/version.h>
> +#include "vmfs_fs.h"
> +#include "vmfsno.h"
> +#include "vmfs_mount.h"
> +
> +#include <asm/system.h>
> +#include <asm/uaccess.h>
> +#include <linux/version.h>
> +
> +#include "vmfs_debug.h"
> +#include "getopt.h"
> +#include "proto.h"
> +
> +#include "messagebox.h"
> +#include "vmfs.h"
> +
> +/* gpb: no reason this has to be in linux/magic.h */
> +
> +#define VMFS_SUPER_MAGIC 0x564D4653 /* VMFS */
> +
> +/* gpb: this needs to be made configurable */
> +
> +#define VMFS_TTL_DEFAULT 1000
> +
> +DEFINE_MUTEX(vmfs_mutex);
> +
> +static void vmfs_delete_inode(struct inode *);
> +static void vmfs_put_super(struct super_block *);
> +static int vmfs_statfs(struct dentry *, struct kstatfs *);
> +static int vmfs_show_options(struct seq_file *, struct vfsmount *);
> +
> +static struct kmem_cache *vmfs_inode_cachep;
> +
> +static MessageBox *mbox;
> +static VFS *vfs;
> +
> +static struct inode *vmfs_alloc_inode(struct super_block *sb)
> +{
> + struct vmfs_inode_info *ei;
> + ei = (struct vmfs_inode_info *)kmem_cache_alloc(vmfs_inode_cachep,
> + GFP_KERNEL);
> + if (!ei)
> + return NULL;
> + return &ei->vfs_inode;
> +}
> +
> +static void vmfs_destroy_inode(struct inode *inode)
> +{
> + kmem_cache_free(vmfs_inode_cachep, VMFS_I(inode));
> +}
> +
> +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 28)
> +static void init_once(void *foo)
> +#else
> +static void init_once(struct kmem_cache *cachep, void *foo)
> +#endif
> +{
> + struct vmfs_inode_info *ei = (struct vmfs_inode_info *)foo;
> +
> + inode_init_once(&ei->vfs_inode);
> +}
> +
> +static int init_inodecache(void)
> +{
> + vmfs_inode_cachep = kmem_cache_create("vmfs_inode_cache",
> + sizeof(struct vmfs_inode_info),
> + 0, (SLAB_RECLAIM_ACCOUNT |
> + SLAB_MEM_SPREAD), init_once);
> + if (vmfs_inode_cachep == NULL)
> + return -ENOMEM;
> + return 0;
> +}
> +
> +static void destroy_inodecache(void)
> +{
> + kmem_cache_destroy(vmfs_inode_cachep);
> +}
> +
> +static int vmfs_remount(struct super_block *sb, int *flags, char *data)
> +{
> + *flags |= MS_NODIRATIME;
> + return 0;
> +}
> +
> +static const struct super_operations vmfs_sops = {
> + .alloc_inode = vmfs_alloc_inode,
> + .destroy_inode = vmfs_destroy_inode,
> + .drop_inode = generic_delete_inode,
> +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 36)
> + .delete_inode = vmfs_delete_inode,
> +#else
> + .evict_inode = vmfs_delete_inode,
> +#endif
> + .put_super = vmfs_put_super,
> + .statfs = vmfs_statfs,
> + .show_options = vmfs_show_options,
> + .remount_fs = vmfs_remount,
> +};
> +
> +/* We are always generating a new inode here */
> +struct inode *vmfs_iget(struct super_block *sb, struct vmfs_fattr *fattr)
> +{
> + struct inode *result;
> +
> + DEBUG1("vmfs_iget: %p\n", fattr);
> +
> + result = new_inode(sb);
> + if (!result)
> + return result;
> + result->i_ino = fattr->f_ino;
> + VMFS_I(result)->open = 0;
> + VMFS_I(result)->closed = 0;
> + VMFS_I(result)->openers = 0;
> + VMFS_I(result)->vhandle = -1;
> + VMFS_I(result)->vaccess = 0;
> + VMFS_I(result)->vopen = 0;
> +
> + vmfs_set_inode_attr(result, fattr);
> + if (S_ISREG(result->i_mode)) {
> + result->i_op = &vmfs_file_inode_operations;
> + result->i_fop = &vmfs_file_operations;
> + result->i_data.a_ops = &vmfs_file_aops;
> + } else if (S_ISDIR(result->i_mode)) {
> + result->i_op = &vmfs_dir_inode_operations_unix;
> + result->i_fop = &vmfs_dir_operations;
> + } else if (S_ISLNK(result->i_mode)) {
> + result->i_op = &vmfs_link_inode_operations;
> + } else {
> + init_special_inode(result, result->i_mode, fattr->f_rdev);
> + }
> + insert_inode_hash(result);
> + return result;
> +}
> +
> +/*
> + * Copy the inode data to a vmfs_fattr structure.
> + */
> +void vmfs_get_inode_attr(struct inode *inode, struct vmfs_fattr *fattr)
> +{
> + memset(fattr, 0, sizeof(struct vmfs_fattr));
> + fattr->f_mode = inode->i_mode;
> + fattr->f_nlink = inode->i_nlink;
> + fattr->f_ino = inode->i_ino;
> + fattr->f_uid = inode->i_uid;
> + fattr->f_gid = inode->i_gid;
> + fattr->f_size = inode->i_size;
> + fattr->f_mtime = inode->i_mtime;
> + fattr->f_ctime = inode->i_ctime;
> + fattr->f_atime = inode->i_atime;
> + fattr->f_blocks = inode->i_blocks;
> +
> +}
> +
> +/*
> + * Update the inode, possibly causing it to invalidate its pages if mtime/size
> + * is different from last time.
> + */
> +void vmfs_set_inode_attr(struct inode *inode, struct vmfs_fattr *fattr)
> +{
> + struct vmfs_inode_info *ei = VMFS_I(inode);
> +
> + /*
> + * A size change should have a different mtime, or same mtime
> + * but different size.
> + */
> + time_t last_time = inode->i_mtime.tv_sec;
> + loff_t last_sz = inode->i_size;
> +
> + inode->i_mode = fattr->f_mode;
> + set_nlink(inode, fattr->f_nlink);
> + inode->i_uid = fattr->f_uid;
> + inode->i_gid = fattr->f_gid;
> + inode->i_ctime = fattr->f_ctime;
> + inode->i_blocks = fattr->f_blocks;
> + inode->i_size = fattr->f_size;
> + inode->i_mtime = fattr->f_mtime;
> + inode->i_atime = fattr->f_atime;
> +
> +
> + /*
> + * Update the "last time refreshed" field for revalidation.
> + */
> + ei->oldmtime = jiffies;
> +
> + if (inode->i_mtime.tv_sec != last_time || inode->i_size != last_sz) {
> + VERBOSE("%ld changed, old=%ld, new=%ld, oz=%ld, nz=%ld\n",
> + inode->i_ino,
> + (long)last_time, (long)inode->i_mtime.tv_sec,
> + (long)last_sz, (long)inode->i_size);
> +
> + if (!S_ISDIR(inode->i_mode))
> + invalidate_remote_inode(inode);
> + }
> +}
> +
> +/*
> + * This is called if the connection has gone bad ...
> + * try to kill off all the current inodes.
> + */
> +void vmfs_invalidate_inodes(struct vmfs_sb_info *server)
> +{
> + VERBOSE("\n");
> + shrink_dcache_sb(SB_of(server));
> +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 37)
> + invalidate_inodes(SB_of(server));
> +#endif
> +}
> +
> +/*
> + * This is called to update the inode attributes after
> + * we've made changes to a file or directory.
> + */
> +static int vmfs_refresh_inode(struct dentry *dentry)
> +{
> + struct inode *inode = dentry->d_inode;
> + int error;
> + struct vmfs_fattr fattr;
> +
> + DEBUG1("");
> +
> + error = vmfs_proc_getattr(dentry, &fattr);
> + if (!error) {
> + vmfs_renew_times(dentry);
> + /*
> + * Check whether the type part of the mode changed,
> + * and don't update the attributes if it did.
> + *
> + * And don't dick with the root inode
> + */
> + if (inode->i_ino == 2)
> + return error;
> + if (S_ISLNK(inode->i_mode))
> + return error; /* VFS will deal with it */
> +
> + if ((inode->i_mode & S_IFMT) == (fattr.f_mode & S_IFMT)) {
> + vmfs_set_inode_attr(inode, &fattr);
> + } else {
> + /*
> + * Big trouble! The inode has become a new object,
> + * so any operations attempted on it are invalid.
> + *
> + * To limit damage, mark the inode as bad so that
> + * subsequent lookup validations will fail.
> + */
> + PARANOIA("%s/%s changed mode, %07o to %07o\n",
> + DENTRY_PATH(dentry),
> + inode->i_mode, fattr.f_mode);
> +
> + fattr.f_mode = inode->i_mode; /* save mode */
> + make_bad_inode(inode);
> + inode->i_mode = fattr.f_mode; /* restore mode */
> + /*
> + * No need to worry about unhashing the dentry: the
> + * lookup validation will see that the inode is bad.
> + * But we do want to invalidate the caches ...
> + */
> + if (!S_ISDIR(inode->i_mode))
> + invalidate_remote_inode(inode);
> + else
> + vmfs_invalid_dir_cache(inode);
> + error = -EIO;
> + }
> + }
> + return error;
> +}
> +
> +/*
> + * This is called when we want to check whether the inode
> + * has changed on the server. If it has changed, we must
> + * invalidate our local caches.
> + */
> +int vmfs_revalidate_inode(struct dentry *dentry)
> +{
> + struct vmfs_sb_info *s = server_from_dentry(dentry);
> + struct inode *inode = dentry->d_inode;
> + int error = 0;
> +
> + DEBUG1("vmfs_revalidate_inode\n");
> +
> + /*
> + * Check whether we've recently refreshed the inode.
> + */
> + if (time_before(jiffies, VMFS_I(inode)->oldmtime + VMFS_MAX_AGE(s))) {
> + VERBOSE("up-to-date, ino=%ld, jiffies=%lu, oldtime=%lu\n",
> + inode->i_ino, jiffies, VMFS_I(inode)->oldmtime);
> + goto out;
> + }
> +
> + error = vmfs_refresh_inode(dentry);
> +out:
> + return error;
> +}
> +
> +/*
> + * This routine is called when i_nlink == 0 and i_count goes to 0.
> + * All blocking cleanup operations need to go here to avoid races.
> + */
> +static void vmfs_delete_inode(struct inode *ino)
> +{
> + DEBUG1("ino=%ld\n", ino->i_ino);
> + truncate_inode_pages(&ino->i_data, 0);
> + mutex_lock(&vmfs_mutex);
> + if (vmfs_close(ino))
> + PARANOIA("could not close inode %ld\n", ino->i_ino);
> + mutex_unlock(&vmfs_mutex);
> +}
> +
> +/*
> + * vmfs_show_options() is for displaying mount options in /proc/mounts.
> + * It tries to avoid showing settings that were not changed from their
> + * defaults.
> + */
> +static int vmfs_show_options(struct seq_file *s, struct vfsmount *m)
> +{
> +
> + return 0;
> +}
> +
> +static void vmfs_put_super(struct super_block *sb)
> +{
> + struct vmfs_sb_info *server = VMFS_SB(sb);
> +
> + mutex_lock(&vmfs_mutex);
> +
> + kfree(server->ops);
> +
> + sb->s_fs_info = NULL;
> +
> + mutex_unlock(&vmfs_mutex);
> + kfree(server);
> +}
> +
> +static int vmfs_fill_super(struct super_block *sb, void *raw_data_unused,
> + int silent)
> +{
> + struct vmfs_sb_info *server;
> + struct vmfs_mount_data_kernel *mnt;
> + struct inode *root_inode;
> + struct vmfs_fattr root;
> + void *mem;
> +
> + sb->s_flags |= MS_NODIRATIME;
> + sb->s_blocksize = 1024;
> + sb->s_blocksize_bits = 10;
> + sb->s_magic = VMFS_SUPER_MAGIC;
> + sb->s_op = &vmfs_sops;
> + sb->s_time_gran = 100;
> +
> + server = kzalloc(sizeof(struct vmfs_sb_info), GFP_KERNEL);
> + if (!server)
> + goto out_no_server;
> + sb->s_fs_info = server;
> +
> + server->super_block = sb;
> + server->mnt = NULL;
> + server->vfs = vfs;
> +
> + sema_init(&server->sem, 1);
> + INIT_LIST_HEAD(&server->entry);
> +
> + /* Allocate global temp buffer and some superblock helper structs */
> + /* FIXME: move these to the vmfs_sb_info struct */
> + VERBOSE("alloc chunk = %u\n", sizeof(struct vmfs_ops) +
> + sizeof(struct vmfs_mount_data_kernel));
> + mem = kmalloc(sizeof(struct vmfs_ops) +
> + sizeof(struct vmfs_mount_data_kernel), GFP_KERNEL);
> + if (!mem)
> + goto out_no_mem;
> +
> + server->ops = mem;
> + vmfs_install_ops(server->ops);
> + server->mnt = mem + sizeof(struct vmfs_ops);
> +
> + mnt = server->mnt;
> +
> + memset(mnt, 0, sizeof(struct vmfs_mount_data_kernel));
> +
> + mnt->ttl = VMFS_TTL_DEFAULT;
> + mnt->file_mode = S_IRWXU | S_IRGRP | S_IXGRP |
> + S_IROTH | S_IXOTH | S_IFREG;
> + mnt->dir_mode = S_IRWXU | S_IRGRP | S_IXGRP |
> + S_IROTH | S_IXOTH | S_IFDIR;
> +
> + mnt->mounted_uid = current->real_cred->uid;
> +
> + /*
> + * Keep the super block locked while we get the root inode.
> + */
> + vmfs_init_root_dirent(server, &root, sb);
> + root_inode = vmfs_iget(sb, &root);
> + if (!root_inode)
> + goto out_no_root;
> +
> + sb->s_root = d_make_root(root_inode);
> + if (!sb->s_root)
> + goto out_no_root;
> +
> + vmfs_new_dentry(sb->s_root);
> +
> + return 0;
> +
> +out_no_root:
> + iput(root_inode);
> + kfree(mem);
> +out_no_mem:
> + if (!server->mnt)
> + printk(KERN_ERR "vmfs_fill_super: allocation failure\n");
> + sb->s_fs_info = NULL;
> + kfree(server);
> + return -EINVAL;
> +out_no_server:
> + printk(KERN_ERR
> + "vmfs_fill_super: cannot allocate struct vmfs_sb_info\n");
> + return -ENOMEM;
> +}
> +
> +static int vmfs_statfs(struct dentry *dentry, struct kstatfs *buf)
> +{
> + int result;
> +
> + mutex_lock(&vmfs_mutex);
> +
> + result = vmfs_proc_dskattr(dentry, buf);
> +
> + mutex_unlock(&vmfs_mutex);
> +
> + buf->f_type = VMFS_SUPER_MAGIC;
> + buf->f_namelen = VMFS_MAXPATHLEN;
> + return result;
> +}
> +
> +int vmfs_getattr(struct vfsmount *mnt, struct dentry *dentry,
> + struct kstat *stat)
> +{
> + int err = vmfs_revalidate_inode(dentry);
> + if (!err)
> + generic_fillattr(dentry->d_inode, stat);
> + return err;
> +}
> +
> +int vmfs_notify_change(struct dentry *dentry, struct iattr *attr)
> +{
> + struct inode *inode = dentry->d_inode;
> + struct vmfs_sb_info *server = server_from_dentry(dentry);
> + unsigned int mask = (S_IFREG | S_IFDIR | S_IRWXUGO);
> + int error, changed, refresh = 0;
> + struct vmfs_fattr fattr;
> +
> + DEBUG1("\n");
> +
> + mutex_lock(&vmfs_mutex);
> +
> + error = vmfs_revalidate_inode(dentry);
> + if (error)
> + goto out;
> +
> + error = inode_change_ok(inode, attr);
> + if (error < 0)
> + goto out;
> +
> + error = -EPERM;
> + if ((attr->ia_valid & ATTR_UID) && (attr->ia_uid != server->mnt->uid))
> + goto out;
> +
> + if ((attr->ia_valid & ATTR_GID) && (attr->ia_uid != server->mnt->gid))
> + goto out;
> +
> + if ((attr->ia_valid & ATTR_MODE) && (attr->ia_mode & ~mask))
> + goto out;
> +
> + if ((attr->ia_valid & ATTR_SIZE) != 0) {
> + VERBOSE("changing %s/%s, old size=%ld, new size=%ld\n",
> + DENTRY_PATH(dentry),
> + (long)inode->i_size, (long)attr->ia_size);
> +
> + filemap_write_and_wait(inode->i_mapping);
> +
> + error = vmfs_open(dentry, 0, O_WRONLY);
> + if (error)
> + goto out;
> + error = server->ops->truncate(inode, attr->ia_size);
> + if (error)
> + goto out;
> + error = vmtruncate(inode, attr->ia_size);
> + if (error)
> + goto out;
> + refresh = 1;
> + }
> +
> + /*
> + * Initialize the fattr and check for changed fields.
> + * Note: CTIME under VMFS is creation time rather than
> + * change time, so we don't attempt to change it.
> + */
> + vmfs_get_inode_attr(inode, &fattr);
> +
> + changed = 0;
> + if ((attr->ia_valid & ATTR_MTIME) != 0) {
> + fattr.f_mtime = attr->ia_mtime;
> + changed = 1;
> + }
> + if ((attr->ia_valid & ATTR_ATIME) != 0) {
> + fattr.f_atime = attr->ia_atime;
> + /* Earlier protocols don't have an access time */
> + }
> + if (changed) {
> + error = vmfs_proc_settime(dentry, &fattr);
> + if (error)
> + goto out;
> + refresh = 1;
> + }
> +
> + /*
> + * Check for mode changes ... we're extremely limited in
> + * what can be set for VMFS servers: just the read-only bit.
> + */
> + if ((attr->ia_valid & ATTR_MODE) != 0) {
> + VERBOSE("%s/%s mode change, old=%x, new=%x\n",
> + DENTRY_PATH(dentry), fattr.f_mode, attr->ia_mode);
> + changed = 0;
> + if (attr->ia_mode & S_IWUSR) {
> + if (fattr.attr & aRONLY) {
> + fattr.attr &= ~aRONLY;
> + changed = 1;
> + }
> + } else {
> + if (!(fattr.attr & aRONLY)) {
> + fattr.attr |= aRONLY;
> + changed = 1;
> + }
> + }
> + if (changed) {
> + error = vmfs_proc_setattr(dentry, &fattr);
> + if (error)
> + goto out;
> + refresh = 1;
> + }
> + }
> + error = 0;
> +
> +out:
> + if (refresh)
> + vmfs_refresh_inode(dentry);
> + mutex_unlock(&vmfs_mutex);
> + return error;
> +}
> +
> +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 39)
> +static int vmfs_get_sb(struct file_system_type *fs_type,
> + int flags, const char *dev_name, void *data,
> + struct vfsmount *mnt)
> +{
> + return get_sb_nodev(fs_type, flags, data, vmfs_fill_super, mnt);
> +}
> +#else
> +static struct dentry *vmfs_do_mount(struct file_system_type *fs_type,
> + int flags, const char *dev_name,
> + void *data)
> +{
> + return mount_nodev(fs_type, flags, data, vmfs_fill_super);
> +}
> +#endif
> +
> +static struct file_system_type vmfs_fs_type = {
> + .owner = THIS_MODULE,
> + .name = "vmfs",
> +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 39)
> + .get_sb = vmfs_get_sb,
> +#else
> + .mount = vmfs_do_mount,
> +#endif
> + .kill_sb = kill_anon_super,
> + .fs_flags = FS_BINARY_MOUNTDATA,
> +};
> +
> +static int __init init_vmfs_fs(void)
> +{
> + int err;
> + DEBUG1("registering ...\n");
> +
> + err = init_inodecache();
> + if (err)
> + goto out_inode;
> +
> + /* map the message box device into memory */
> +
> + mbox = mb_new(CONFIG_VMFS_DEV_BASE, CONFIG_VMFS_IRQ);
> +
> + if (mbox == NULL) {
> + err = -1;
> + goto out_inode;
> + }
> +
> + vfs = vfsop_new(mbox);
> + if (vfs == NULL) {
> + err = -1;
> + goto out_mbox;
> + }
> +
> + err = register_filesystem(&vmfs_fs_type);
> + if (err)
> + goto out;
> + return 0;
> +out:
> + destroy_inodecache();
> + vfsop_delete(vfs);
> +out_mbox:
> + mb_delete(mbox);
> +out_inode:
> + return err;
> +}
> +
> +static void __exit exit_vmfs_fs(void)
> +{
> + DEBUG1("unregistering ...\n");
> + unregister_filesystem(&vmfs_fs_type);
> +
> + vfsop_delete(vfs);
> + mb_delete(mbox);
> +
> + destroy_inodecache();
> +}
> +
> +module_init(init_vmfs_fs)
> + module_exit(exit_vmfs_fs)
> + MODULE_LICENSE("GPL");
> diff --git a/fs/vmfs/ioctl.c b/fs/vmfs/ioctl.c
> new file mode 100644
> index 0000000..b08531e
> --- /dev/null
> +++ b/fs/vmfs/ioctl.c
> @@ -0,0 +1,49 @@
> +/*
> + * ioctl.c
> + *
> + * Copyright (C) 1995, 1996 by Volker Lendecke
> + * Copyright (C) 1997 by Volker Lendecke
> + *
> + * Copyright (C) 2008-2009 ARM Limited
> + *
> + * Please add a note about your changes to vmfs_ in the ChangeLog file.
> + */
> +
> +#include <linux/errno.h>
> +#include <linux/fs.h>
> +#include <linux/ioctl.h>
> +#include <linux/time.h>
> +#include <linux/mm.h>
> +#include <linux/highuid.h>
> +
> +#include "vmfs_fs.h"
> +#include "vmfs_mount.h"
> +
> +#include <asm/uaccess.h>
> +
> +#include "proto.h"
> +
> +long vmfs_unlocked_ioctl(struct file *filp, unsigned int cmd,
> + unsigned long arg)
> +{
> + struct inode *inode = filp->f_path.dentry->d_inode;
> + struct vmfs_sb_info *server = server_from_inode(inode);
> + int result = -EINVAL;
> +
> + switch (cmd) {
> + uid16_t uid16;
> + uid_t uid32;
> + case VMFS_IOC_GETMOUNTUID:
> + SET_UID(uid16, server->mnt->mounted_uid);
> + result = put_user(uid16, (uid16_t __user *) arg);
> + break;
> + case VMFS_IOC_GETMOUNTUID32:
> + SET_UID(uid32, server->mnt->mounted_uid);
> + result = put_user(uid32, (uid_t __user *) arg);
> + break;
> + default:
> + break;
> + }
> +
> + return result;
> +}
> diff --git a/fs/vmfs/mboxtypes.h b/fs/vmfs/mboxtypes.h
> new file mode 100644
> index 0000000..54c4ebd
> --- /dev/null
> +++ b/fs/vmfs/mboxtypes.h
> @@ -0,0 +1,31 @@
> +/*
> + * Copyright 2008-2009 ARM Limited. All rights reserved.
> + */
> +
> +/*
> + * Messagebox definitions shared between messagebox device and driver
> + */
> +
> +#ifndef MBOXTYPES_H
> +#define MBOXTYPES_H
> +
> +enum MessageBoxDefs {
> + MBOX_CONTROL_START = 1, /* start sending a message */
> + MBOX_CONTROL_END = 2, /* end sending a message */
> + MBOX_CONTROL_CANCEL = 3, /* cancel sending a message */
> +
> + MBOX_STATUS_RXEMPTY = (1 << 0), /* no more incoming message data */
> + MBOX_STATUS_TXFULL = (1 << 1), /* no room for an outgoing message */
> + MBOX_STATUS_RXREADY = (1 << 2), /* a new incoming message is
> + ready to be received */
> +
> + MBOX_REGISTER_BASE = 0x0, /* base of device registers */
> + MBOX_REGISTER_SIZE = 0x1000, /* size of register region */
> +
> + MBOX_BUFFER_BASE = 0x1000, /* base of shared buffer */
> + MBOX_BUFFER_SIZE = 0xf000, /* size of buffer region */
> +
> + MBOX_DEVICE_SIZE = MBOX_REGISTER_SIZE + MBOX_BUFFER_SIZE
> +};
> +
> +#endif /* MBOXTYPES_H */
> diff --git a/fs/vmfs/messagebox.c b/fs/vmfs/messagebox.c
> new file mode 100644
> index 0000000..8494493
> --- /dev/null
> +++ b/fs/vmfs/messagebox.c
> @@ -0,0 +1,314 @@
> +/*
> + * Copyright 2008-2009 ARM Limited. All rights reserved.
> + */
> +
> +/*
> + Very simple linux 2.6 implementation of a messagebox
> + for passing messages (data) between the vm and a device.
> +
> + Currently this implements just enough to satisfy the needs of VFS
> +
> + There are lots of TODOs here:
> + clean up the device interface
> + add support for delayed message response (PENDING vs OK/ERROR)
> + add support for multiple users (vmfs currently does the locking)
> +*/
> +
> +#include <linux/types.h>
> +#include <linux/mm.h>
> +#include <linux/io.h>
> +#include <linux/ioport.h>
> +#include <linux/kernel.h>
> +#include <linux/interrupt.h>
> +#include <linux/version.h>
> +#include <linux/sched.h>
> +#include <linux/slab.h>
> +#include <linux/semaphore.h>
> +
> +#include "vmfs_debug.h"
> +
> +#include "mboxtypes.h"
> +#include "messagebox.h"
> +
> +
> +/* Define this to make the driver use PIO rather than memory mapped access */
> +/* #define USE_PIO */
> +
> +/* Define this to use interrupts rather than polling */
> +#define USE_IRQ
> +
> +/* Message box device register layout in memory */
> +
> +struct MBRegs {
> + uint32_t id;
> + uint32_t data;
> + uint32_t control;
> + uint32_t status;
> + uint32_t start;
> + uint32_t end;
> + uint32_t irqmask;
> +} MBRegs;
> +
> +struct MessageBox {
> + volatile struct MBRegs *dev; /* virtual base of registers */
> +
> + uint32_t dev_base; /* physical base of registers */
> + uint32_t dev_irq; /* irq number of device */
> + uint32_t *buffer; /* fixed size buffer used for passing data */
> +
> +#ifdef USE_IRQ
> + /* if we use IRQs then the calling thread must be able to sleep */
> + /* and be woken by the IRQ handler. for this we appear to need a */
> + /* wait queue */
> + wait_queue_head_t irq_queue;
> + spinlock_t irq_lock;
> +#endif
> +
> + uint32_t use_irq; /* set to true if we're using irq's
> + * rather than polling */
> +
> + struct semaphore mb_access; /* semaphore to allow only one thread
> + * to access the message box */
> +};
> +
> +#ifdef USE_IRQ
> +static irqreturn_t mb_interrupt(int irq, void *dev_id)
> +{
> + MessageBox *mb = (MessageBox *) dev_id;
> +
> + FNENTER("");
> +
> + /* should be safe to access the device here,
> + * or do we need to spinlock?
> + */
> + spin_lock(&mb->irq_lock);
> +
> + /* disable all interrupts, we only use RXREADY */
> + writel(0, &mb->dev->irqmask);
> +
> + /* wake up any thread waiting on the queue */
> + wake_up_interruptible(&mb->irq_queue);
> +
> + spin_unlock(&mb->irq_lock);
> +
> + FNEXIT("");
> +
> + return IRQ_HANDLED;
> +}
> +#endif /* USE_IRQ */
> +
> +/* Initialise OS structures involved in serialising access to the messagebox */
> +MessageBox *mb_new(phys_addr_t dev_base, uint32_t dev_irq)
> +{
> + MessageBox *mb;
> +
> + DEBUG1("initialising at 0x%x ...\n", dev_base);
> +
> + mb = (MessageBox *) kmalloc(sizeof(MessageBox), GFP_KERNEL);
> +
> + /* Map the messagebox registers and buffer int VM */
> +
> + if (check_mem_region(dev_base, MBOX_DEVICE_SIZE)) {
> + DEBUG1("i/o space at 0x%x already in use\n", dev_base);
> + return NULL;
> + }
> +
> + request_mem_region(dev_base, MBOX_DEVICE_SIZE, "messagebox");
> +
> + mb->dev = ioremap_nocache(dev_base, MBOX_DEVICE_SIZE);
> +
> + DEBUG1("device registers mapped at %p, size 0x%x\n", mb->dev,
> + MBOX_DEVICE_SIZE);
> +
> +#ifdef USE_PIO
> + mb->buffer = (uint32_t *) kmalloc(MBOX_BUFFER_SIZE, GFP_KERNEL);
> +#else
> + mb->buffer = (uint32_t *) ((uint8_t *) mb->dev + MBOX_BUFFER_BASE);
> +#endif
> +
> + /* optionally request an interrupt source */
> +
> +#ifdef USE_IRQ
> + mb->dev_irq = dev_irq;
> + mb->use_irq = 1;
> + if (request_irq(dev_irq, mb_interrupt, 0, "VFS", mb)) {
> + DEBUG1("failed to register irq %d\n", dev_irq);
> + mb->use_irq = 0;
> + }
> +
> + init_waitqueue_head(&mb->irq_queue);
> + spin_lock_init(&mb->irq_lock);
> +#endif
> +
> + /* set up a semaphore to restrict access to the message box */
> +
> + sema_init(&mb->mb_access, 1);
> +
> + DEBUG1("initialised %p, id=0x%x\n", mb, mb_id(mb));
> +
> + return mb;
> +}
> +
> +void mb_delete(MessageBox *mb)
> +{
> +#ifdef USE_IRQ
> + if (mb->use_irq)
> + free_irq(mb->dev_irq, mb);
> +#endif
> +
> + iounmap(mb->dev);
> +
> + release_mem_region(mb->dev_base, MBOX_DEVICE_SIZE);
> +
> +#ifdef USE_PIO
> + kfree(mb->buffer);
> +#endif
> +
> + kfree(mb);
> +}
> +
> +/* the message box should be locked by the thread
> + * during the send/receive cycle
> + */
> +int mb_lock(MessageBox *mb)
> +{
> + return down_interruptible(&mb->mb_access);
> +}
> +
> +void mb_unlock(MessageBox *mb)
> +{
> + up(&mb->mb_access);
> +}
> +
> +void *mb_start(MessageBox *mb, uint32_t len)
> +{
> + /* start a message
> + *
> + * Current implementation expects exclusive access to the device
> + * from mb_start to mb_end and through to mb_receive.
> + */
> + writel(MBOX_CONTROL_START, &mb->dev->control);
> +
> + /* reset buffer pointers
> + */
> + writel(0, &mb->dev->start);
> + writel(0, &mb->dev->end);
> +
> + return mb->buffer;
> +}
> +
> +int mb_end(MessageBox *mb, uint32_t len)
> +{
> +#ifdef USE_PIO
> + uint32_t *buffer = mb->buffer;
> +
> + len = len / 4;
> +
> + while (len > 0) {
> + writel(*buffer++, &mb->dev->data);
> + --len;
> + }
> +#else
> + writel(len, &mb->dev->end);
> +#endif
> +
> + /* Indicate to the device that all the buffered data is now written
> + */
> + writel(MBOX_CONTROL_END, &mb->dev->control);
> +
> + /* current implementation will set RXREADY to true to indicate
> + * that the return data is available
> + */
> + return mb_ready(mb);
> +}
> +
> +/* Indicate whether there is receive data ready to read */
> +int mb_ready(MessageBox *mb)
> +{
> + return (readl(&mb->dev->status) & MBOX_STATUS_RXREADY) != 0;
> +}
> +
> +/* Wait for the reply to become ready */
> +int mb_wait(MessageBox *mb)
> +{
> +#ifdef USE_IRQ
> + if (mb->use_irq) {
> + /* add our thread to the irq wait queue */
> + DECLARE_WAITQUEUE(wait, current);
> +
> + add_wait_queue(&mb->irq_queue, &wait);
> + do {
> + /* make ourself sleep interruptible */
> + set_current_state(TASK_INTERRUPTIBLE);
> +
> + /* enable RXREADY interrupt */
> + spin_lock_irq(&mb->irq_lock);
> + writel(MBOX_STATUS_RXREADY, &mb->dev->irqmask);
> + spin_unlock_irq(&mb->irq_lock);
> +
> + DEBUG1("sleeping");
> +
> + /* sleep */
> + schedule();
> +
> + DEBUG1("waking");
> +
> + /* once there is data ready, break out */
> + if (mb_ready(mb))
> + break;
> +
> + /* if we were interrupted also break out */
> + if (signal_pending(current))
> + break;
> + } while (1);
> +
> + /* back to normal */
> + remove_wait_queue(&mb->irq_queue, &wait);
> +
> + set_current_state(TASK_RUNNING);
> +
> + /* ensure interrupts are masked out */
> + spin_lock_irq(&mb->irq_lock);
> + writel(0, &mb->dev->irqmask);
> + spin_unlock_irq(&mb->irq_lock);
> +
> + if (!mb_ready(mb))
> + return -EINTR;
> + }
> +#endif
> +
> + while (!mb_ready(mb))
> + schedule();
> +
> + return 0;
> +}
> +
> +void *mb_receive(MessageBox *mb, uint32_t *len)
> +{
> +#ifdef USE_PIO
> + uint32_t *buffer = mb->buffer;
> + uint32_t bidx = 0;
> +
> + /* read data from the device until there is no more to receive
> + */
> +
> + while ((readl(&mb->dev->status) & MBOX_STATUS_RXEMPTY) == 0)
> + buffer[bidx++] = readl(&mb->dev->data);
> +
> + *len = bidx * 4;
> +
> + return mb->buffer;
> +#else
> + uint32_t start = readl(&mb->dev->start);
> + uint32_t end = readl(&mb->dev->end);
> +
> + *len = end - start;
> +
> + return mb->buffer + start;
> +#endif
> +}
> +
> +uint32_t mb_id(MessageBox *mb)
> +{
> + return readl(&mb->dev->id);
> +}
> diff --git a/fs/vmfs/messagebox.h b/fs/vmfs/messagebox.h
> new file mode 100644
> index 0000000..cadb097
> --- /dev/null
> +++ b/fs/vmfs/messagebox.h
> @@ -0,0 +1,121 @@
> +/*
> + * Copyright 2008-2009 ARM Limited. All rights reserved.
> + */
> +
> +/*!
> + * \file messagebox.h
> + * \brief driver for simple messagebox device
> + *
> + */
> +
> +/*! Defines the interface to a simple messagebox device driver
> + *
> + * The intention with the messagebox device is to provide a very simple
> + * interface for sending and receiving packets of information to the host
> + * side device. It should be possible to encapsulate all target OS locking
> + * and barriers within the messagebox.
> + *
> + * The current implementation is very basic, supporting enough functionality
> + * for the VFS blocking model to work correctly.
> + *
> + * TODO:
> + * split the interface so that the buffer is allocated/freed
> + * separate to send/receive?
> + */
> +
> +#ifndef MESSAGEBOX_H
> +#define MESSAGEBOX_H
> +
> +/*! Opaque handle for message box operations */
> +typedef struct MessageBox MessageBox;
> +
> +/*! Instantiate a new messagebox driver
> + *
> + * \param dev_base physical base address of device registers+buffer
> + * \param dev_irq irq number of device
> + *
> + * \return opaque message box structure for use in other calls
> + */
> +MessageBox *mb_new(phys_addr_t dev_base, uint32_t dev_irq);
> +
> +/*! free resources assocuated with the messagebox handle
> + *
> + * \param mb messagebox handle
> + */
> +void mb_delete(MessageBox *mb);
> +
> +/*! Reserve resources for sending a message
> + *
> + * \param mb messagebox handle
> + * \param len maximum length of message that will be sent
> + *
> + * \returns pointer to buffer to fill with message
> + */
> +void *mb_start(MessageBox *mb, uint32_t len);
> +
> +/*! Send and release the buffer obtained with mb_start
> + *
> + * \param mb messagebox handle
> + * \param len actual length of message in buffer
> + *
> + * \return non-zero if a reply message is ready to be received
> + */
> +int mb_end(MessageBox *mb, uint32_t len);
> +
> +/*! Check whether receive data is available
> + *
> + * \param mb messagebox handle
> + *
> + * \return 1 for data available. 0 for none available
> + *
> + * Allows drivers to poll for receive data (rather than using interrupts)
> + */
> +int mb_ready(MessageBox *mb);
> +
> +/*! Wait for receive data to become available
> + *
> + * \param mb messagebox handle
> + *
> + * \return 0 for data available. -ve for error (e.g. -EINTR)
> + *
> + * This function will block until there is receive data available
> + */
> +int mb_wait(MessageBox *mb);
> +
> +/*! lock the messagebox for exclusive access by a thread
> + *
> + * \param mb messagebox handle
> + *
> + * \return 0 for lockable, -ve for error (e.g. -EINTR)
> + *
> + * This function will block until the message box is free and locked,
> + * or until the thread is interrupted
> + */
> +int mb_lock(MessageBox *mb);
> +
> +/*! unlock the messagebox and allow it to be used by another thread
> + *
> + * \param mb messagebox handle
> + */
> +void mb_unlock(MessageBox *mb);
> +
> +/*! Receive an incoming (reply) message
> + *
> + * \param mb messagebox handle
> + * \param len pointer to instance to receive length of message
> + *
> + * \return pointer to buffer containing received message
> + *
> + * Message data should be copied from the buffer before the call returns
> + */
> +void *mb_receive(MessageBox *mb, uint32_t *len);
> +
> +/*! Get the device configured id
> + *
> + * \param mb messagebox handle
> + *
> + * \return value configured in the 'id' parameter in the lisa model
> + */
> +uint32_t mb_id(MessageBox *mb);
> +
> +#endif /* MESSAGEBOX_H */
> diff --git a/fs/vmfs/msg.c b/fs/vmfs/msg.c
> new file mode 100644
> index 0000000..0c811fe
> --- /dev/null
> +++ b/fs/vmfs/msg.c
> @@ -0,0 +1,232 @@
> +/*
> + * Copyright 2008-2009 ARM Limited. All rights reserved.
> + */
> +
> +/*
> + * Utility types/functions for constructing/deconstructing blocks
> + * of data to be sent over a message box between the target and host
> + * (and vice versa) this implementation is converted to be
> + * used in the linux kernel. These must match the behaviour in
> + * the equivalent C++ classes used on the host side
> + */
> +
> +#include <linux/kernel.h>
> +#include <linux/types.h>
> +#include <linux/mm.h>
> +#include <linux/string.h>
> +#include <linux/slab.h>
> +
> +#include "msg.h"
> +
> +typedef enum MsgDataType {
> + MSG_END, /* (potential) marker for end of message data */
> + MSG_UINT32, /* 32 bit data */
> + MSG_UINT64, /* 64 bit data */
> + MSG_INT32, /* 32 bit data */
> + MSG_CSTR, /* zero terminated c string */
> + MSG_DATA, /* raw data */
> + MSG_CHAR, /* single character */
> + MSG_BOOL /* packed int? */
> +} MsgDataType;
> +
> +typedef enum MsgTraits {
> + TYPE_SHIFT = 0,
> + TYPE_BITS = 8,
> + TYPE_MASK = (1 << TYPE_BITS) - 1,
> +
> + LEN_SHIFT = TYPE_BITS,
> + LEN_BITS = 20,
> + MAX_LEN = 1 << LEN_BITS,
> + LEN_MASK = MAX_LEN - 1
> +} MsgTraits;
> +
> +struct MessageComposer {
> + uint8_t *b_data; /* message data */
> + uint32_t b_size; /* buffer size */
> + uint32_t b_index; /* offset to next byte to fill */
> +};
> +
> +void msgc_init(MessageComposer *mc, void *data, uint32_t len)
> +{
> + mc->b_data = data;
> + mc->b_size = len;
> + mc->b_index = 0;
> +}
> +
> +void msgc_cleanup(MessageComposer *mc)
> +{
> +}
> +
> +MessageComposer *msgc_new(void *data, uint32_t len)
> +{
> + MessageComposer *mc =
> + (MessageComposer *) kmalloc(sizeof(struct MessageComposer),
> + GFP_KERNEL);
> +
> + msgc_init(mc, data, len);
> +
> + return mc;
> +}
> +
> +void msgc_delete(MessageComposer *mc)
> +{
> + msgc_cleanup(mc);
> + kfree(mc);
> +}
> +
> +static int msgc_put(MessageComposer *mc, MsgDataType type, const void *data,
> + uint32_t len)
> +{
> + uint32_t tag;
> +
> + if (len >= mc->b_size)
> + return 0;
> +
> + if (!mc->b_data)
> + return 0;
> +
> + tag = (len << LEN_SHIFT) | ((uint32_t) type);
> +
> + *(uint32_t *) (mc->b_data + mc->b_index) = tag;
> + mc->b_index += 4;
> +
> + memcpy(mc->b_data + mc->b_index, data, len);
> + mc->b_index += len;
> +
> + mc->b_index = (mc->b_index + 3) & ~3; /* word align */
> +
> + return 1;
> +}
> +
> +int msgc_put_int32(MessageComposer *mc, int32_t data)
> +{
> + return msgc_put(mc, MSG_INT32, (void *)&data, sizeof(int32_t));
> +}
> +
> +int msgc_put_uint32(MessageComposer *mc, uint32_t data)
> +{
> + return msgc_put(mc, MSG_UINT32, (void *)&data, sizeof(uint32_t));
> +}
> +
> +int msgc_put_uint64(MessageComposer *mc, uint64_t data)
> +{
> + return msgc_put(mc, MSG_UINT64, (void *)&data, sizeof(uint64_t));
> +}
> +
> +int msgc_put_cstr(MessageComposer *mc, const char *data)
> +{
> + return msgc_put(mc, MSG_CSTR, (void *)data, strlen(data) + 1);
> +}
> +
> +int msgc_put_data(MessageComposer *mc, const void *data, uint32_t len)
> +{
> + return msgc_put(mc, MSG_DATA, data, len);
> +}
> +
> +
> +uint32_t msgc_get_size(MessageComposer *mc)
> +{
> + return mc->b_index;
> +}
> +
> +struct MessageDecomposer {
> + const uint8_t *b_data; /* message data */
> + uint32_t b_size; /* size of buffer */
> + uint32_t b_index; /* current index into buffer */
> +};
> +
> +static int msgd_get(MessageDecomposer *md, MsgDataType type, void *data,
> + uint32_t *len)
> +{
> + uint32_t tag;
> + uint32_t d_len;
> + MsgDataType d_type;
> +
> + if (md->b_index + 4 > md->b_size)
> + return 0;
> +
> + tag = *(uint32_t *) (md->b_data + md->b_index);
> +
> + d_type = (MsgDataType) ((tag >> TYPE_SHIFT) & TYPE_MASK);
> + d_len = ((tag >> LEN_SHIFT) & LEN_MASK);
> +
> + if (d_type != type)
> + return 0;
> +
> + md->b_index += 4;
> +
> + if (md->b_index + d_len > md->b_size)
> + return 0;
> +
> + if (*len > d_len)
> + *len = d_len;
> +
> + memcpy(data, md->b_data + md->b_index, *len);
> +
> + md->b_index += d_len;
> +
> + md->b_index = (md->b_index + 3) & ~3; /* word align */
> +
> + return 1;
> +}
> +
> +void msgd_init(MessageDecomposer *md, const void *data, uint32_t len)
> +{
> + md->b_data = (const unsigned char *)data;
> + md->b_size = len;
> + md->b_index = 0;
> +}
> +
> +void msgd_cleanup(MessageDecomposer *md)
> +{
> +}
> +
> +MessageDecomposer *msgd_new(const void *data, uint32_t len)
> +{
> + MessageDecomposer *md =
> + (MessageDecomposer *) kmalloc(sizeof(struct MessageDecomposer),
> + GFP_KERNEL);
> +
> + msgd_init(md, data, len);
> +
> + return md;
> +}
> +
> +void msgd_delete(MessageDecomposer *md)
> +{
> + msgd_cleanup(md);
> + kfree(md);
> +}
> +
> +/* for decomposing */
> +
> +int msgd_get_int32(MessageDecomposer *md, int32_t *data)
> +{
> + uint32_t len = sizeof(int32_t);
> +
> + return msgd_get(md, MSG_INT32, (void *)data, &len);
> +}
> +
> +int msgd_get_uint32(MessageDecomposer *md, uint32_t *data)
> +{
> + uint32_t len = sizeof(uint32_t);
> +
> + return msgd_get(md, MSG_UINT32, (void *)data, &len);
> +}
> +
> +int msgd_get_uint64(MessageDecomposer *md, uint64_t *data)
> +{
> + uint32_t len = sizeof(uint64_t);
> +
> + return msgd_get(md, MSG_UINT64, (void *)data, &len);
> +}
> +
> +int msgd_get_cstr(MessageDecomposer *md, char *data, unsigned int *len)
> +{
> + return msgd_get(md, MSG_CSTR, (void *)data, len);
> +}
> +
> +int msgd_get_data(MessageDecomposer *md, void *data, uint32_t *len)
> +{
> + return msgd_get(md, MSG_DATA, data, len);
> +}
> diff --git a/fs/vmfs/msg.h b/fs/vmfs/msg.h
> new file mode 100644
> index 0000000..4bc0dfd
> --- /dev/null
> +++ b/fs/vmfs/msg.h
> @@ -0,0 +1,182 @@
> +/*
> + * Copyright 2008-2009 ARM Limited. All rights reserved.
> + */
> +
> +/*!
> + * \file msg.h
> + * \brief objects and functions to covert function
> + * calls into messages and back
> + * \todo change return codes, and define some errors
> + */
> +
> +#ifndef MSG_H
> +#define MSG_H
> +
> +/*! opaque type for an object that can compose messages */
> +typedef struct MessageComposer MessageComposer;
> +
> +/*! instantiate a new message composer object that can
> + * compose a message into the supplied buffer
> + *
> + * \param data buffer into which messages can be composed (may be NULL)
> + * \param len size of buffer (may be 0)
> + *
> + * \return message composer object
> + */
> +MessageComposer *msgc_new(void *data, uint32_t len);
> +
> +/*! destroy a message composer object
> + *
> + * \param mc message composer object
> + */
> +void msgc_delete(MessageComposer *mc);
> +
> +/*! (re)initialise a message composer object to use a new buffer
> + *
> + * \param mc message composer object
> + * \param data buffer into which messages can be composed (may be NULL)
> + * \param len size of buffer (may be 0)
> + */
> +void msgc_init(MessageComposer *mc, void *data, uint32_t len);
> +
> +/*! disassociate a message composer object from a buffer
> + *
> + * \param mc message composer object
> + */
> +void msgc_cleanup(MessageComposer *mc);
> +
> +/*! add a signed integer to the message
> + *
> + * \param mc message composer object
> + * \param data data to add to message
> + *
> + * \return 1 for success, 0 for fail
> + */
> +int msgc_put_int32(MessageComposer *mc, int32_t data);
> +
> +/*! add an unsigned signed integer to the message
> + *
> + * \param mc message composer object
> + * \param data data to add to message
> + *
> + * \return 1 for success, 0 for fail
> + */
> +int msgc_put_uint32(MessageComposer *mc, uint32_t data);
> +
> +/*! add an unsigned 64bit integer to the message
> + *
> + * \param mc message composer object
> + * \param data data to add to message
> + *
> + * \return 1 for success, 0 for fail
> + */
> +int msgc_put_uint64(MessageComposer *mc, uint64_t data);
> +
> +/*! add a zero terminated string to the message
> + *
> + * \param mc message composer object
> + * \param data data to add to message
> + *
> + * \return 1 for success, 0 for fail
> + */
> +int msgc_put_cstr(MessageComposer *mc, const char *data);
> +
> +/*! add a data block the message
> + *
> + * \param mc message composer object
> + * \param data data to add to message
> + * \param len length of data to add to the message
> + *
> + * \return 1 for success, 0 for fail
> + */
> +int msgc_put_data(MessageComposer *mc, const void *data, uint32_t len);
> +
> +/*! return the current size of the message in bytes
> + *
> + * \param mc message composer object
> + *
> + * \return size of the message in bytes
> + */
> +uint32_t msgc_get_size(MessageComposer *mc);
> +
> +/*! opaque type for an object that can decompose messages */
> +typedef struct MessageDecomposer MessageDecomposer;
> +
> +/*! instantiate a new message decomposer object that can decompose
> + * a message from the supplied buffer
> + *
> + * \param data buffer from which messages can be decomposed (may be NULL)
> + * \param len size of buffer (may be 0)
> + *
> + * \return message decomposer object
> + */
> +MessageDecomposer *msgd_new(const void *data, uint32_t len);
> +
> +/*! destroy a message decomposer object
> + *
> + * \param md message decomposer object
> + */
> +void msgd_delete(MessageDecomposer *md);
> +
> +/*! (re)initialise a message decomposer object to use a new buffer
> + *
> + * \param md message decomposer object
> + * \param data buffer from which messages can be decomposed (may be NULL)
> + * \param len size of buffer (may be 0)
> + */
> +void msgd_init(MessageDecomposer *md, const void *data, uint32_t len);
> +
> +/*! disassociate a message decomposer object from a buffer
> + *
> + * \param md message decomposer object
> + */
> +void msgd_cleanup(MessageDecomposer *md);
> +
> +/*! extract a signed integer from the message
> + *
> + * \param md message decomposer object
> + * \param data data to extract from message
> + *
> + * \return 1 for success, 0 for fail
> + */
> +int msgd_get_int32(MessageDecomposer *md, int32_t *data);
> +
> +/*! extract an unsigned integer from the message
> + *
> + * \param md message decomposer object
> + * \param data data to extract from message
> + *
> + * \return 1 for success, 0 for fail
> + */
> +int msgd_get_uint32(MessageDecomposer *md, uint32_t *data);
> +
> +/*! extract an unsigned 64 bit integer from the message
> + *
> + * \param md message decomposer object
> + * \param data data to extract from message
> + *
> + * \return 1 for success, 0 for fail
> + */
> +int msgd_get_uint64(MessageDecomposer *md, uint64_t *data);
> +
> +/*! extract a zero terminated C string from the message
> + *
> + * \param md message decomposer object
> + * \param data data to extract from message
> + * \param len in: max length to extract, out: length of string extracted
> + *
> + * \return 1 for success, 0 for fail
> + */
> +int msgd_get_cstr(MessageDecomposer *md, char *data, unsigned int *len);
> +
> +/*! extract a data block from the message
> + *
> + * \param md message decomposer object
> + * \param data data to extract from message
> + * \param len in: max length to extract, out: length of data extracted
> + *
> + * \return 1 for success, 0 for fail
> + */
> +int msgd_get_data(MessageDecomposer *md, void *data, uint32_t *len);
> +
> +#endif /* MSG_H */
> diff --git a/fs/vmfs/proc.c b/fs/vmfs/proc.c
> new file mode 100644
> index 0000000..be6f77b
> --- /dev/null
> +++ b/fs/vmfs/proc.c
> @@ -0,0 +1,1086 @@
> +/*
> + * proc.c
> + *
> + * Copyright (C) 1995, 1996 by Paal-Kr. Engstad and Volker Lendecke
> + * Copyright (C) 1997 by Volker Lendecke
> + *
> + * Please add a note about your changes to vmfs_ in the ChangeLog file.
> + *
> + * Copyright (C) 2008-2009 by ARM Limited
> + */
> +
> +#include <linux/types.h>
> +#include <linux/capability.h>
> +#include <linux/errno.h>
> +#include <linux/slab.h>
> +#include <linux/fs.h>
> +#include <linux/file.h>
> +#include <linux/stat.h>
> +#include <linux/fcntl.h>
> +#include <linux/dcache.h>
> +#include <linux/dirent.h>
> +#include <linux/vfs.h>
> +#include <linux/version.h>
> +#include "vmfs_fs.h"
> +#include "vmfsno.h"
> +#include "vmfs_mount.h"
> +
> +#include <asm/string.h>
> +#include <asm/div64.h>
> +
> +#include "vmfs_debug.h"
> +#include "proto.h"
> +#include "vfs.h"
> +
> +/* Features. Undefine if they cause problems, this should perhaps be a
> + config option. */
> +#define VMFSFS_POSIX_UNLINK 1
> +
> +#define VMFS_ST_BLKSIZE (PAGE_SIZE)
> +#define VMFS_ST_BLKSHIFT (PAGE_SHIFT)
> +
> +/* dont seem to have ulldiv. This is good enough for / 1000 */
> +static uint64_t divmod64(uint64_t dividend, uint32_t divisor,
> + uint32_t *remainder)
> +{
> + uint64_t quotient = 0;
> + uint32_t pquot, prem = 0;
> + uint32_t i;
> +
> + /* divide in 4 32x16->32 bit parts. As most ARMs don't have / anyway
> + * we should probably do this bit by bit */
> + for (i = 0; i < 4; ++i) {
> + uint32_t part = (prem << 16) | (dividend >> 48);
> +
> + pquot = part / divisor;
> + prem = part % divisor;
> +
> + dividend = dividend << 16;
> + quotient = (quotient << 16) | pquot;
> + }
> +
> + if (remainder)
> + *remainder = prem;
> +
> + return quotient;
> +}
> +
> +
> +#define VMFS_ATTR_MAX (PATH_MAX+256)
> +
> +struct vmfs_ws {
> + char path[PATH_MAX];
> + char path2[PATH_MAX];
> + uint8_t attr[VMFS_ATTR_MAX];
> +};
> +
> +static struct vmfs_ws *vmfs_get_ws(struct vmfs_sb_info *server)
> +{
> + return kmalloc(sizeof(struct vmfs_ws), GFP_NOFS);
> +}
> +
> +static void vmfs_put_ws(struct vmfs_ws *ws)
> +{
> + kfree(ws);
> +}
> +
> +/*****************************************************************************/
> +/* */
> +/* Encoding/Decoding section */
> +/* */
> +/*****************************************************************************/
> +
> +/*
> + * vmfs_build_path: build the path to entry and name storing it in buf.
> + * The path returned will have the trailing '\0'.
> + */
> +static int vmfs_build_path(struct vmfs_sb_info *server, unsigned char *buf,
> + int buflen, struct dentry *entry, struct qstr *name)
> +{
> + unsigned char *path = buf;
> + int maxlen = buflen;
> + int len;
> +
> + VERBOSE("for dir %s\n", entry->d_name.name);
> +
> + if (maxlen > VMFS_MAXPATHLEN + 1)
> + maxlen = VMFS_MAXPATHLEN + 1;
> +
> + if (maxlen < 1)
> + return -ENAMETOOLONG;
> +
> + path = buf + buflen;
> + *--path = '\0';
> + --maxlen;
> +
> + if (name) {
> + len = name->len + 1;
> +
> + if (len > maxlen)
> + return -ENAMETOOLONG;
> +
> + path -= len;
> + maxlen -= len;
> + memcpy(path, name->name, len);
> +
> + *--path = '/';
> + --maxlen;
> + }
> +
> + if (entry != NULL) {
> + dget(entry);
> + do {
> + struct dentry *parent;
> +
> + len = entry->d_name.len;
> +
> + /* +1 for separator */
> + if (len + 1 > maxlen) {
> + dput(entry);
> + return -ENAMETOOLONG;
> + }
> +
> + spin_lock(&entry->d_lock);
> + path -= len;
> + maxlen -= len;
> + memcpy(path, entry->d_name.name, len);
> +
> + *--path = '/';
> + --maxlen;
> +
> +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 37)
> + parent = entry->d_parent;
> + dget(parent);
> + spin_unlock(&entry->d_lock);
> +#else
> + spin_unlock(&entry->d_lock);
> + parent = dget_parent(entry);
> +#endif
> + dput(entry);
> + entry = parent;
> + } while (!IS_ROOT(entry));
> + dput(entry);
> + }
> + /* at the root we need to put on the root prefix, which is held
> + * in the server
> + * TODO - for now we assume it is called 'A' */
> +
> + if (maxlen < 2)
> + return -ENAMETOOLONG;
> +
> + maxlen -= 2;
> + *--path = ':';
> + *--path = 'A';
> +
> + len = buflen - maxlen;
> + memmove(buf, path, len);
> +
> + return len;
> +}
> +
> +static int vmfs_encode_path(struct vmfs_sb_info *server, char *buf, int maxlen,
> + struct dentry *dir, struct qstr *name)
> +{
> + int result;
> +
> + result = vmfs_build_path(server, buf, maxlen, dir, name);
> + if (result < 0)
> + goto out;
> +
> +out:
> + FNEXIT("%d", result);
> +
> + return result;
> +}
> +
> +
> +/*****************************************************************************/
> +/* */
> +/* Support section. */
> +/* */
> +/*****************************************************************************/
> +
> +/*
> + * Convert VMFS error codes to -E... errno values.
> + */
> +int vmfs_errno(int error)
> +{
> + if (error < 0) {
> + VERBOSE("%d\n", error);
> +
> + switch (error) {
> + case VFS_ERR_BADHANDLE:
> + return -EBADF;
> + case VFS_ERR_NOENTRY:
> + return -ENOENT;
> + case VFS_ERR_NOROOM:
> + return -ENOMEM;
> + case VFS_ERR_MAXHANDLE:
> + return -EMFILE;
> + case VFS_ERR_NOMOUNT:
> + return -ENXIO;
> + case VFS_ERR_NOTFOUND:
> + return -ENOENT;
> + case VFS_ERR_PERM:
> + return -EACCES; /* EPERM? */
> + case VFS_ERR_NOTDIR:
> + return -ENOTDIR;
> + case VFS_ERR_TOOLONG:
> + return -ENAMETOOLONG;
> + case VFS_ERR_EXIST:
> + return -EEXIST;
> + case VFS_ERR_NOTEMPTY:
> + return -ENOTEMPTY;
> + case VFS_ERR_INVALID:
> + return -EINVAL;
> + case VFS_ERR_ISDIR:
> + return -EISDIR;
> + case VFS_ERR_TOOBIG:
> + return -ERANGE;
> + case VFS_ERR_UNIMPL:
> + return -ENOSYS;
> +
> + default:
> + /* something generic */
> + return -EIO;
> + }
> + } else
> + return error;
> +}
> +
> +static int
> +vmfs_proc_open(struct vmfs_sb_info *server, struct dentry *dentry, int wish)
> +{
> + struct inode *ino = dentry->d_inode;
> + struct vmfs_inode_info *ei = VMFS_I(ino);
> + VFSOpenFlags mode = wish;
> + int res;
> + struct vmfs_ws *ws = vmfs_get_ws(server);
> +
> + FNENTER();
> +
> + if (!(ino->i_mode & (S_IWUSR | S_IWGRP | S_IWOTH)))
> + mode &= ~VFS_OPEN_WRONLY;
> +
> + res = vmfs_encode_path(server, ws->path, PATH_MAX, dentry, NULL);
> + if (res < 0)
> + goto out;
> +
> + res = vfsop_openfile(server->vfs, ws->path, mode);
> + if ((res < 0) && ((mode & VFS_OPEN_RDWR) == VFS_OPEN_RDWR)) {
> + mode &= ~VFS_OPEN_WRONLY;
> + res = vfsop_openfile(server->vfs, ws->path, mode);
> + }
> +
> + if (res < 0) {
> + res = vmfs_errno(res);
> + goto out;
> + }
> + /* we appear to need attribute information also. Not sure why.
> + * res = vfsop_getattr(server->vfs, p, VFS_ATTR_, attr, attrlen); */
> +
> + ei->vhandle = res;
> + ei->vaccess = mode & VFS_OPEN_RDWR;
> + ei->vopen = 1;
> +
> + /* may want to set up attr (as in dos attr) here, and access */
> +
> + res = 0;
> +out:
> + vmfs_put_ws(ws);
> +
> + FNEXIT("%d\n", res);
> + return res;
> +}
> +
> +/*
> + * Make sure the file is open, and check that the access
> + * is compatible with the desired access.
> + *
> + * wish is one of VMFS_O_RDONLY = 0/VMFS_O_WRONLY = 1/VMFS_O_RDWR = 2
> + */
> +int vmfs_open(struct dentry *dentry, int flags, int wish)
> +{
> + struct inode *inode = dentry->d_inode;
> + int result;
> + VFSOpenFlags vwish, vaccess;
> +
> + FNENTER();
> +
> + if (wish == VMFS_O_RDONLY)
> + vwish = VFS_OPEN_RDONLY;
> + else if (wish == VMFS_O_WRONLY)
> + vwish = VFS_OPEN_WRONLY;
> + else if (wish == VMFS_O_RDWR)
> + vwish = VFS_OPEN_RDWR;
> + else {
> + DEBUG1("unexpected open flags!\n");
> + vwish = VFS_OPEN_RDWR;
> + }
> +
> + if (flags & O_CREAT)
> + vwish |= VFS_OPEN_CREATE;
> + if (flags & O_TRUNC)
> + vwish |= VFS_OPEN_TRUNCATE;
> + if (flags & O_EXCL)
> + vwish |= VFS_OPEN_NEW;
> +
> + result = -ENOENT;
> + if (!inode) {
> + printk(KERN_ERR "vmfs_open: no inode for dentry!\n");
> + goto out;
> + }
> +
> + if (!vmfs_is_open(inode)) {
> + struct vmfs_sb_info *server = server_from_inode(inode);
> + result = 0;
> + if (!vmfs_is_open(inode))
> + result = vmfs_proc_open(server, dentry, vwish);
> + if (result)
> + goto out;
> + /*
> + * A successful open means the path is still valid ...
> + */
> + vmfs_renew_times(dentry);
> + }
> +
> + /*
> + * Check whether the access is compatible with the desired mode.
> + */
> +
> + result = 0;
> + vaccess = VMFS_I(inode)->vaccess;
> +
> + if (vaccess != (vwish & VFS_OPEN_RDWR) && vaccess != VFS_OPEN_RDWR) {
> + PARANOIA("%s/%s access denied, access=%x, wish=%x\n",
> + DENTRY_PATH(dentry), vaccess, vwish);
> + result = -EACCES;
> + }
> +out:
> + FNEXIT("%d", result);
> + return result;
> +}
> +
> +static int vmfs_proc_close(struct vmfs_sb_info *server, int32_t handle)
> +{
> + int result = -ENOMEM;
> +
> + FNENTER();
> +
> + result = vmfs_errno(vfsop_closefile(server->vfs, handle));
> +
> + /* GPBTODO - may need to set mtime using utc2local(server, mtime) */
> +
> + FNEXIT("%d", result);
> +
> + return result;
> +}
> +
> +/*
> + * Win NT 4.0 has an apparent bug in that it fails to update the
> + * modify time when writing to a file. As a workaround, we update
> + * both modify and access time locally, and post the times to the
> + * server when closing the file.
> + */
> +static int vmfs_proc_close_inode(struct vmfs_sb_info *server,
> + struct inode *ino)
> +{
> + struct vmfs_inode_info *ei = VMFS_I(ino);
> + int result = 0;
> + if (vmfs_is_open(ino)) {
> + /*
> + * We clear the open flag in advance, in case another
> + * process observes the value while we block below.
> + */
> + ei->vopen = 0;
> +
> + result = vmfs_proc_close(server, ei->vhandle);
> +
> + ei->closed = jiffies;
> + }
> +
> + FNEXIT("%d", result);
> +
> + return result;
> +}
> +
> +int vmfs_close(struct inode *ino)
> +{
> + int result = 0;
> +
> + if (vmfs_is_open(ino)) {
> + struct vmfs_sb_info *server = server_from_inode(ino);
> + result = vmfs_proc_close_inode(server, ino);
> + }
> +
> + FNEXIT("%d", result);
> +
> + return result;
> +}
> +
> +/*
> + * This is used to close a file following a failed instantiate.
> + * Since we don't have an inode, we can't use any of the above.
> + */
> +int vmfs_close_fileid(struct dentry *dentry, int32_t fileid)
> +{
> +
> + struct vmfs_sb_info *server = server_from_dentry(dentry);
> + int result;
> +
> + result = vmfs_proc_close(server, fileid);
> +
> + FNEXIT("%d", result);
> +
> + return result;
> +}
> +
> +static int
> +vmfs_proc_read(struct inode *inode, loff_t offset, int count, char *data)
> +{
> + struct vmfs_sb_info *server = server_from_inode(inode);
> + int result;
> +
> + result =
> + vfsop_readfile(server->vfs, VMFS_I(inode)->vhandle, offset, data,
> + count);
> + if (result < 0)
> + result = vmfs_errno(result);
> +
> + VERBOSE("ino=%ld, handle=%d, count=%d, result=%d\n",
> + inode->i_ino, VMFS_I(inode)->vhandle, count, result);
> +
> + return result;
> +}
> +
> +static int
> +vmfs_proc_write(struct inode *inode, loff_t offset,
> + int count, const char *data)
> +{
> + struct vmfs_sb_info *server = server_from_inode(inode);
> + int result;
> +
> + result =
> + vfsop_writefile(server->vfs, VMFS_I(inode)->vhandle, offset, data,
> + count);
> + if (result < 0)
> + result = vmfs_errno(result);
> +
> + VERBOSE("ino=%ld, handle=%d, count=%d, result=%d\n",
> + inode->i_ino, VMFS_I(inode)->vhandle, count, result);
> + return result;
> +}
> +
> +/* GPB - this appears to be open(O_CREAT) which we do support */
> +int vmfs_proc_create(struct dentry *dentry, uint32_t mode, int32_t *fileid)
> +{
> + struct vmfs_sb_info *server = server_from_dentry(dentry);
> + struct vmfs_ws *ws = vmfs_get_ws(server);
> + int result;
> +
> + result = vmfs_encode_path(server, ws->path, PATH_MAX, dentry, NULL);
> + if (result < 0)
> + goto out;
> +
> + result =
> + vfsop_openfile(server->vfs, ws->path,
> + VFS_OPEN_CREATE | VFS_OPEN_RDWR);
> + if (result < 0) {
> + result = vmfs_errno(result);
> + goto out;
> + }
> + /* GPBTODO - may need to set mtime when file is created */
> + /* GPBTODO - what should create do if the file already exists? */
> +
> + *fileid = result;
> + result = 0;
> +
> +out:
> + vmfs_put_ws(ws);
> + FNEXIT("%d", result);
> + return result;
> +}
> +
> +int vmfs_proc_mv(struct dentry *old_dentry, struct dentry *new_dentry)
> +{
> + struct vmfs_sb_info *server = server_from_dentry(old_dentry);
> + struct vmfs_ws *ws = vmfs_get_ws(server);
> +
> + int result;
> +
> + result =
> + vmfs_encode_path(server, ws->path, PATH_MAX, old_dentry, NULL);
> + if (result < 0)
> + goto out;
> + result =
> + vmfs_encode_path(server, ws->path2, PATH_MAX, new_dentry, NULL);
> + if (result < 0)
> + goto out;
> +
> + result = vmfs_errno(vfsop_rename(server->vfs, ws->path, ws->path2));
> + if (result < 0)
> + goto out;
> +
> + result = 0;
> +
> +out:
> + vmfs_put_ws(ws);
> + FNEXIT("%d", result);
> + return result;
> +}
> +
> +int vmfs_proc_mkdir(struct dentry *dentry)
> +{
> + struct vmfs_sb_info *server = server_from_dentry(dentry);
> + struct vmfs_ws *ws = vmfs_get_ws(server);
> + int result;
> +
> + FNENTER();
> +
> + result = vmfs_encode_path(server, ws->path, PATH_MAX, dentry, NULL);
> + if (result < 0)
> + goto out;
> +
> + result = vmfs_errno(vfsop_mkdir(server->vfs, ws->path));
> + if (result < 0)
> + goto out;
> +
> + result = 0;
> +
> +out:
> + vmfs_put_ws(ws);
> +
> + FNEXIT("%d", result);
> +
> + return result;
> +}
> +
> +int vmfs_proc_rmdir(struct dentry *dentry)
> +{
> + struct vmfs_sb_info *server = server_from_dentry(dentry);
> + struct vmfs_ws *ws = vmfs_get_ws(server);
> + int result;
> +
> + FNENTER();
> +
> + result = vmfs_encode_path(server, ws->path, PATH_MAX, dentry, NULL);
> + if (result < 0)
> + goto out;
> +
> + result = vmfs_errno(vfsop_rmdir(server->vfs, ws->path));
> + if (result < 0)
> + goto out;
> +
> + result = 0;
> +
> +out:
> + vmfs_put_ws(ws);
> +
> + FNEXIT("%d", result);
> +
> + return result;
> +}
> +
> +#if VMFSFS_POSIX_UNLINK
> +/*
> + * Removes readonly attribute from a file. Used by unlink to give posix
> + * semantics.
> + */
> +#endif
> +
> +int vmfs_proc_unlink(struct dentry *dentry)
> +{
> + struct vmfs_sb_info *server = server_from_dentry(dentry);
> + struct vmfs_ws *ws = vmfs_get_ws(server);
> + int result;
> +
> + result = vmfs_encode_path(server, ws->path, PATH_MAX, dentry, NULL);
> + if (result < 0)
> + goto out;
> +
> + /* GPBTODO - this needs to work even if the file is read only
> + * should this be done on the host side? */
> +
> + result = vmfs_errno(vfsop_remove(server->vfs, ws->path));
> +out:
> + vmfs_put_ws(ws);
> +
> + FNEXIT("%d", result);
> +
> + return result;
> +}
> +
> +int vmfs_proc_flush(struct vmfs_sb_info *server, int32_t handle)
> +{
> + int result;
> +
> + result = vmfs_errno(vfsop_filesync(server->vfs, handle));
> +
> + FNEXIT("%d", result);
> +
> + return result;
> +}
> +
> +static int vmfs_proc_trunc32(struct inode *inode, loff_t length)
> +{
> + struct vmfs_sb_info *server = server_from_inode(inode);
> + int result;
> +
> + result =
> + vmfs_errno(vfsop_setfilesize
> + (server->vfs, VMFS_I(inode)->vhandle, length));
> + if (result < 0)
> + goto out;
> +
> + result = 0;
> +
> + FNEXIT("%d", result);
> +
> +out:
> + return result;
> +}
> +
> +static void
> +vmfs_init_dirent(struct vmfs_sb_info *server, struct vmfs_fattr *fattr)
> +{
> + memset(fattr, 0, sizeof(*fattr));
> +
> + fattr->f_nlink = 1;
> + fattr->f_uid = server->mnt->uid;
> + fattr->f_gid = server->mnt->gid;
> + fattr->f_unix = 0;
> +}
> +
> +static void
> +vmfs_finish_dirent(struct vmfs_sb_info *server, struct vmfs_fattr *fattr)
> +{
> + if (fattr->f_unix)
> + return;
> +
> + fattr->f_mode = server->mnt->file_mode;
> + if (fattr->attr & aDIR) {
> + fattr->f_mode = server->mnt->dir_mode;
> + fattr->f_size = VMFS_ST_BLKSIZE;
> + }
> + /* Check the read-only flag */
> + if (fattr->attr & aRONLY)
> + fattr->f_mode &= ~(S_IWUSR | S_IWGRP | S_IWOTH);
> +
> + /* How many 512 byte blocks do we need for this file? */
> + fattr->f_blocks = 0;
> + if (fattr->f_size != 0)
> + fattr->f_blocks = 1 + ((fattr->f_size - 1) >> 9);
> + return;
> +}
> +
> +void
> +vmfs_init_root_dirent(struct vmfs_sb_info *server, struct vmfs_fattr *fattr,
> + struct super_block *sb)
> +{
> + vmfs_init_dirent(server, fattr);
> + fattr->attr = aDIR;
> + fattr->f_ino = 2; /* traditional root inode number */
> + fattr->f_mtime = current_fs_time(sb);
> + vmfs_finish_dirent(server, fattr);
> +}
> +
> +/*
> + * read in directory entries into the dentry cache
> + */
> +static int
> +vmfs_proc_readdir_long(struct file *filp, void *dirent, filldir_t filldir,
> + struct vmfs_cache_control *ctl)
> +{
> + struct dentry *dir = filp->f_path.dentry;
> + struct vmfs_sb_info *server = server_from_dentry(dir);
> + struct vmfs_ws *ws = vmfs_get_ws(server);
> + int vhandle;
> + struct vmfs_fattr fattr;
> + struct qstr qname;
> + int result;
> +
> + result = vmfs_encode_path(server, ws->path, PATH_MAX, dir, NULL);
> + if (result < 0)
> + goto out;
> +
> + result = vfsop_opendir(server->vfs, ws->path);
> + if (result < 0) {
> + result = vmfs_errno(result);
> + goto out;
> + }
> +
> + vhandle = result;
> +
> + while (result >= 0) {
> + uint32_t attrlen = VMFS_ATTR_MAX;
> + uint8_t *attrdata = ws->attr;
> + uint32_t attr =
> + VFS_ATTR_MTIME | VFS_ATTR_TYPE | VFS_ATTR_SIZE |
> + VFS_ATTR_CTIME | VFS_ATTR_ATIME | VFS_ATTR_NAME;
> + uint64_t mtime, ctime, atime;
> + VFSAttr ftype;
> + uint64_t fsize;
> + char *fname;
> +
> + /* todo - get other attributes */
> + result =
> + vmfs_errno(vfsop_readdir
> + (server->vfs, vhandle, attr, (void *)attrdata,
> + attrlen));
> + if (result < 0) {
> + if (result == -ENOENT)
> + result = 0;
> +
> + break;
> + }
> +
> + mtime = *(uint64_t *) attrdata;
> + attrdata += sizeof(uint64_t);
> + ftype = *(uint32_t *) attrdata;
> + attrdata += sizeof(uint32_t);
> + fsize = *(uint64_t *) attrdata;
> + attrdata += sizeof(uint64_t);
> + ctime = *(uint64_t *) attrdata;
> + attrdata += sizeof(uint64_t);
> + atime = *(uint64_t *) attrdata;
> + attrdata += sizeof(uint64_t);
> + fname = (char *)attrdata;
> +
> + if (fname[0] == '.'
> + && ((fname[1] == 0) || (fname[1] == '.' && fname[2] == 0)))
> + continue;
> +
> + /* todo - decode attr */
> + vmfs_init_dirent(server, &fattr);
> + fattr.f_ino = 0;
> +
> + /* mtime/ctime/atime are ms since linux epoch */
> + {
> + uint32_t div, mod;
> +
> + div = (uint32_t) divmod64(mtime, 1000, &mod);
> +
> + fattr.f_mtime.tv_sec = div;
> + fattr.f_mtime.tv_nsec = mod * 1000000;
> + }
> +
> + {
> + uint32_t div, mod;
> +
> + div = (uint32_t) divmod64(ctime, 1000, &mod);
> +
> + fattr.f_ctime.tv_sec = div;
> + fattr.f_ctime.tv_nsec = mod * 1000000;
> + }
> +
> + {
> + uint32_t div, mod;
> +
> + div = (uint32_t) divmod64(atime, 1000, &mod);
> +
> + fattr.f_atime.tv_sec = div;
> + fattr.f_atime.tv_nsec = mod * 1000000;
> + }
> +
> + fattr.f_size = fsize;
> + fattr.attr = 0;
> + if (ftype == (VFSAttr)VFS_TYPE_DIR)
> + fattr.attr |= aDIR;
> +
> + qname.name = fname;
> + qname.len = strlen(fname);
> +
> + vmfs_finish_dirent(server, &fattr);
> +
> + if (!vmfs_fill_cache
> + (filp, dirent, filldir, ctl, &qname, &fattr)) {
> + /* smbfs carries on here... */
> + }
> + }
> +
> + vfsop_closedir(server->vfs, vhandle);
> +
> +out:
> + vmfs_put_ws(ws);
> +
> + FNEXIT("%d", result);
> +
> + return result;
> +}
> +
> +static int
> +vmfs_proc_getattr_unix(struct vmfs_sb_info *server, struct dentry *dir,
> + struct vmfs_fattr *fattr)
> +{
> + struct vmfs_ws *ws = vmfs_get_ws(server);
> + int attr;
> + uint8_t *attrdata = ws->attr;
> + int attrlen = VMFS_ATTR_MAX;
> + uint64_t mtime, ctime, atime;
> + enum VFSType ftype;
> + uint64_t fsize;
> + char *fname;
> + int result;
> +
> + result = vmfs_encode_path(server, ws->path, PATH_MAX, dir, NULL);
> + if (result < 0)
> + goto out;
> +
> + attr =
> + VFS_ATTR_MTIME | VFS_ATTR_TYPE | VFS_ATTR_SIZE | VFS_ATTR_CTIME |
> + VFS_ATTR_ATIME | VFS_ATTR_NAME;
> + result =
> + vmfs_errno(vfsop_getattr
> + (server->vfs, ws->path, attr, (void *)attrdata,
> + attrlen));
> + if (result < 0)
> + goto out;
> +
> + mtime = *(uint64_t *) attrdata;
> + attrdata += sizeof(uint64_t);
> + ftype = *(uint32_t *) attrdata;
> + attrdata += sizeof(uint32_t);
> +
> + /* GPBTODO - return this as an error code, why two codes? */
> + if (ftype == VFS_TYPE_NONE || ftype == VFS_TYPE_UNKNOWN) {
> + result = -ENOENT;
> + goto out;
> + }
> +
> + fsize = *(uint64_t *) attrdata;
> + attrdata += sizeof(uint64_t);
> + ctime = *(uint64_t *) attrdata;
> + attrdata += sizeof(uint64_t);
> + atime = *(uint64_t *) attrdata;
> + attrdata += sizeof(uint64_t);
> + fname = (char *)(attrdata + 20);
> +
> + vmfs_init_dirent(server, fattr);
> + {
> + uint32_t div, mod;
> +
> + div = (uint32_t) divmod64(mtime, 1000, &mod);
> +
> + fattr->f_mtime.tv_sec = div;
> + fattr->f_mtime.tv_nsec = mod * 1000000;
> + }
> +
> + {
> + uint32_t div, mod;
> +
> + div = (uint32_t) divmod64(ctime, 1000, &mod);
> +
> + fattr->f_ctime.tv_sec = div;
> + fattr->f_ctime.tv_nsec = mod * 1000000;
> + }
> +
> + {
> + uint32_t div, mod;
> +
> + div = (uint32_t) divmod64(atime, 1000, &mod);
> +
> + fattr->f_atime.tv_sec = div;
> + fattr->f_atime.tv_nsec = mod * 1000000;
> + }
> +
> + fattr->f_size = fsize;
> +
> + fattr->attr = 0;
> + if (ftype == VFS_TYPE_DIR)
> + fattr->attr |= aDIR;
> +
> + vmfs_finish_dirent(server, fattr);
> +
> +out:
> + vmfs_put_ws(ws);
> +
> + FNEXIT("%d", result);
> +
> + return result;
> +}
> +
> +int vmfs_proc_getattr(struct dentry *dir, struct vmfs_fattr *fattr)
> +{
> + struct vmfs_sb_info *server = server_from_dentry(dir);
> + int result;
> +
> + vmfs_init_dirent(server, fattr);
> + result = server->ops->getattr(server, dir, fattr);
> + vmfs_finish_dirent(server, fattr);
> +
> + FNEXIT("%d", result);
> +
> + return result;
> +}
> +
> +/*
> + * Because of bugs in the trans2 setattr messages, we must set
> + * attributes and timestamps separately. The core VMFSsetatr
> + * message seems to be the only reliable way to set attributes.
> + */
> +int vmfs_proc_setattr(struct dentry *dir, struct vmfs_fattr *fattr)
> +{
> + struct vmfs_sb_info *server = server_from_dentry(dir);
> + struct vmfs_ws *ws = vmfs_get_ws(server);
> + int result;
> +
> + result = vmfs_encode_path(server, ws->path, PATH_MAX, dir, NULL);
> + if (result < 0)
> + goto out;
> +
> + VERBOSE("setting %s/%s, open=%d\n",
> + DENTRY_PATH(dir), vmfs_is_open(dir->d_inode));
> +
> + result = 0;
> +
> +out:
> + vmfs_put_ws(ws);
> +
> + FNEXIT("%d", result);
> +
> + return result;
> +}
> +
> +/*
> + * Set the modify and access timestamps for a file.
> + */
> +int vmfs_proc_settime(struct dentry *dentry, struct vmfs_fattr *fattr)
> +{
> + struct vmfs_sb_info *server = server_from_dentry(dentry);
> + struct vmfs_ws *ws = vmfs_get_ws(server);
> + int result;
> +
> + result = vmfs_encode_path(server, ws->path, PATH_MAX, dentry, NULL);
> + if (result < 0)
> + goto out;
> + result = 0;
> +
> +out:
> + vmfs_put_ws(ws);
> +
> + FNEXIT("%d", result);
> +
> + return result;
> +}
> +
> +int vmfs_proc_dskattr(struct dentry *dentry, struct kstatfs *kattr)
> +{
> + int result;
> + struct vmfs_sb_info *server = VMFS_SB(dentry->d_sb);
> + struct vmfs_ws *ws = vmfs_get_ws(server);
> + uint32_t attr = VFS_ATTR_DISKSIZE | VFS_ATTR_DISKFREE;
> + uint8_t *attrdata = ws->attr;
> + uint32_t attrlen = 16;
> + uint64_t disksize, diskfree;
> +
> + result = vmfs_encode_path(server, ws->path, PATH_MAX, dentry, NULL);
> + if (result < 0)
> + goto out;
> +
> + result =
> + vmfs_errno(vfsop_getattr
> + (server->vfs, ws->path, attr, (void *)attrdata,
> + attrlen));
> + if (result < 0)
> + goto out;
> +
> + disksize = *(uint64_t *) attrdata;
> + diskfree = *(uint64_t *) (attrdata + 8);
> +
> + kattr->f_bsize = VMFS_ST_BLKSIZE;
> + kattr->f_blocks = disksize >> VMFS_ST_BLKSHIFT;
> + kattr->f_bavail = diskfree >> VMFS_ST_BLKSHIFT;
> +
> + result = 0;
> +out:
> + vmfs_put_ws(ws);
> +
> + FNEXIT("%d", result);
> +
> + return result;
> +}
> +
> +/* vfs may not support this operation
> + */
> +
> +int
> +vmfs_proc_read_link(struct vmfs_sb_info *server, struct dentry *dentry,
> + char *buffer, int len)
> +{
> + int result;
> + struct vmfs_ws *ws = vmfs_get_ws(server);
> +
> + result = vmfs_encode_path(server, ws->path, PATH_MAX, dentry, NULL);
> + if (result < 0)
> + goto out;
> +
> + result =
> + vmfs_errno(vfsop_readlink(server->vfs, ws->path, buffer, len));
> + if (result < 0)
> + goto out;
> +
> + buffer[len - 1] = 0;
> + result = strlen(buffer);
> +
> +out:
> + vmfs_put_ws(ws);
> +
> + FNEXIT("%d", result);
> +
> + return result;
> +}
> +
> +/*
> + * Create a symlink object called dentry which points to oldpath.
> + * vfs may not support this operation
> + */
> +int
> +vmfs_proc_symlink(struct vmfs_sb_info *server, struct dentry *dentry,
> + const char *oldpath)
> +{
> + int result;
> + struct vmfs_ws *ws = vmfs_get_ws(server);
> +
> + result = vmfs_encode_path(server, ws->path, PATH_MAX, dentry, NULL);
> + if (result < 0)
> + goto out;
> +
> + result = vmfs_errno(vfsop_symlink(server->vfs, ws->path, oldpath));
> +
> +out:
> + vmfs_put_ws(ws);
> +
> + FNEXIT("%d", result);
> +
> + return result;
> +}
> +
> +/*
> + * Create a hard link object called new_dentry which points to dentry.
> + */
> +int
> +vmfs_proc_link(struct vmfs_sb_info *server, struct dentry *dentry,
> + struct dentry *new_dentry)
> +{
> + /* we don't support hard links */
> + return -EPERM;
> +}
> +
> +static void install_ops(struct vmfs_ops *dst, struct vmfs_ops *src)
> +{
> + memcpy(dst, src, sizeof(void *) * VMFS_OPS_NUM_STATIC);
> +}
> +
> +static struct vmfs_ops vmfs_server_ops = {
> + .read = vmfs_proc_read,
> + .write = vmfs_proc_write,
> + .readdir = vmfs_proc_readdir_long,
> + .getattr = vmfs_proc_getattr_unix,
> + /* .setattr = vmfs_proc_setattr_unix, */
> + .truncate = vmfs_proc_trunc32,
> +};
> +
> +void vmfs_install_ops(struct vmfs_ops *ops)
> +{
> + install_ops(ops, &vmfs_server_ops);
> +}
> diff --git a/fs/vmfs/proto.h b/fs/vmfs/proto.h
> new file mode 100644
> index 0000000..01ea8ed
> --- /dev/null
> +++ b/fs/vmfs/proto.h
> @@ -0,0 +1,71 @@
> +/*
> + * Autogenerated with cproto on: Thu May 8 12:58:52 BST 2008
> + */
> +
> +struct vmfs_request;
> +struct sock;
> +struct statfs;
> +
> +/* proc.c */
> +extern int vmfs_errno(int error);
> +extern int vmfs_open(struct dentry *dentry, int flags, int wish);
> +extern int vmfs_close(struct inode *ino);
> +extern int vmfs_close_fileid(struct dentry *dentry, int32_t fileid);
> +extern int vmfs_proc_create(struct dentry *dentry, uint32_t mode,
> + int32_t *fileid);
> +extern int vmfs_proc_mv(struct dentry *old_dentry, struct dentry *new_dentry);
> +extern int vmfs_proc_mkdir(struct dentry *dentry);
> +extern int vmfs_proc_rmdir(struct dentry *dentry);
> +extern int vmfs_proc_unlink(struct dentry *dentry);
> +extern int vmfs_proc_flush(struct vmfs_sb_info *server, int32_t handle);
> +extern void vmfs_init_root_dirent(struct vmfs_sb_info *server,
> + struct vmfs_fattr *fattr,
> + struct super_block *sb);
> +extern int vmfs_proc_getattr(struct dentry *dir, struct vmfs_fattr *fattr);
> +extern int vmfs_proc_setattr(struct dentry *dir, struct vmfs_fattr *fattr);
> +extern int vmfs_proc_settime(struct dentry *dentry, struct vmfs_fattr *fattr);
> +extern int vmfs_proc_dskattr(struct dentry *dentry, struct kstatfs *kattr);
> +extern int vmfs_proc_read_link(struct vmfs_sb_info *server,
> + struct dentry *dentry, char *buffer, int len);
> +extern int vmfs_proc_symlink(struct vmfs_sb_info *server,
> + struct dentry *dentry,
> + const char *oldpath);
> +extern int vmfs_proc_link(struct vmfs_sb_info *server, struct dentry *dentry,
> + struct dentry *new_dentry);
> +extern void vmfs_install_ops(struct vmfs_ops *ops);
> +/* dir.c */
> +extern const struct file_operations vmfs_dir_operations;
> +extern const struct inode_operations vmfs_dir_inode_operations;
> +extern const struct inode_operations vmfs_dir_inode_operations_unix;
> +extern void vmfs_new_dentry(struct dentry *dentry);
> +extern void vmfs_renew_times(struct dentry *dentry);
> +/* cache.c */
> +extern int vmfs_fill_cache(struct file *filp, void *dirent, filldir_t filldir,
> + struct vmfs_cache_control *ctrl, struct qstr *qname,
> + struct vmfs_fattr *entry);
> +extern void vmfs_invalid_dir_cache(struct inode *dir);
> +extern void vmfs_invalidate_dircache_entries(struct dentry *parent);
> +extern struct dentry *vmfs_dget_fpos(struct dentry *dentry,
> + struct dentry *parent,
> + unsigned long fpos);
> +/* inode.c */
> +extern struct inode *vmfs_iget(struct super_block *sb,
> + struct vmfs_fattr *fattr);
> +extern void vmfs_get_inode_attr(struct inode *inode, struct vmfs_fattr *fattr);
> +extern void vmfs_set_inode_attr(struct inode *inode, struct vmfs_fattr *fattr);
> +extern void vmfs_invalidate_inodes(struct vmfs_sb_info *server);
> +extern int vmfs_revalidate_inode(struct dentry *dentry);
> +extern int vmfs_getattr(struct vfsmount *mnt, struct dentry *dentry,
> + struct kstat *stat);
> +extern int vmfs_notify_change(struct dentry *dentry, struct iattr *attr);
> +/* file.c */
> +extern const struct address_space_operations vmfs_file_aops;
> +extern const struct file_operations vmfs_file_operations;
> +extern const struct inode_operations vmfs_file_inode_operations;
> +/* ioctl.c */
> +extern long vmfs_unlocked_ioctl(struct file *filp, unsigned int cmd,
> + unsigned long arg);
> +/* symlink.c */
> +extern int vmfs_symlink(struct inode *inode, struct dentry *dentry,
> + const char *oldname);
> +extern const struct inode_operations vmfs_link_inode_operations;
> diff --git a/fs/vmfs/symlink.c b/fs/vmfs/symlink.c
> new file mode 100644
> index 0000000..b5dcf3d
> --- /dev/null
> +++ b/fs/vmfs/symlink.c
> @@ -0,0 +1,68 @@
> +/*
> + * symlink.c
> + *
> + * Copyright (C) 2002 by John Newbigin
> + *
> + * Please add a note about your changes to vmfs_ in the ChangeLog file.
> + */
> +
> +#include <linux/kernel.h>
> +#include <linux/errno.h>
> +#include <linux/fcntl.h>
> +#include <linux/stat.h>
> +#include <linux/mm.h>
> +#include <linux/slab.h>
> +#include <linux/pagemap.h>
> +#include <linux/net.h>
> +#include <linux/namei.h>
> +
> +#include <asm/uaccess.h>
> +#include <asm/system.h>
> +
> +#include "vmfsno.h"
> +#include "vmfs_fs.h"
> +
> +#include "vmfs_debug.h"
> +#include "proto.h"
> +
> +int vmfs_symlink(struct inode *inode, struct dentry *dentry,
> + const char *oldname)
> +{
> + DEBUG1("create symlink %s -> %s/%s\n", oldname, DENTRY_PATH(dentry));
> +
> + return vmfs_proc_symlink(server_from_dentry(dentry), dentry, oldname);
> +}
> +
> +static void *vmfs_follow_link(struct dentry *dentry, struct nameidata *nd)
> +{
> + char *link = __getname();
> + DEBUG1("followlink of %s/%s\n", DENTRY_PATH(dentry));
> +
> + if (!link) {
> + link = ERR_PTR(-ENOMEM);
> + } else {
> + int len = vmfs_proc_read_link(server_from_dentry(dentry),
> + dentry, link, PATH_MAX - 1);
> + if (len < 0) {
> + __putname(link);
> + link = ERR_PTR(len);
> + } else {
> + link[len] = 0;
> + }
> + }
> + nd_set_link(nd, link);
> + return NULL;
> +}
> +
> +static void vmfs_put_link(struct dentry *dentry, struct nameidata *nd, void *p)
> +{
> + char *s = nd_get_link(nd);
> + if (!IS_ERR(s))
> + __putname(s);
> +}
> +
> +const struct inode_operations vmfs_link_inode_operations = {
> + .readlink = generic_readlink,
> + .follow_link = vmfs_follow_link,
> + .put_link = vmfs_put_link,
> +};
> diff --git a/fs/vmfs/vfs.c b/fs/vmfs/vfs.c
> new file mode 100644
> index 0000000..a5891dc
> --- /dev/null
> +++ b/fs/vmfs/vfs.c
> @@ -0,0 +1,577 @@
> +/*
> + * Copyright 2008-2009 ARM Limited. All rights reserved.
> + */
> +
> +/*!
> + * \file vfs.cpp
> + * \brief target side vfs implementation in C
> + *
> + * The vfs functions have been renamed to vfsop to avoid
> + * symbol clashes in linux. We should standardise on one or the other.
> + */
> +
> +/* linux kernel requires different includes */
> +
> +#include <linux/mm.h>
> +#include <linux/string.h>
> +#include <linux/types.h>
> +#include <linux/slab.h>
> +
> +#include "messagebox.h"
> +#include "msg.h"
> +#include "vfs.h"
> +
> +/********************************************************************
> + * vfs layer implementation
> + *
> + * VFS operations - these must match those defined in VFS.h
> + ********************************************************************/
> +typedef enum VFSOp {
> + VFS_OPENMOUNTS,
> + VFS_READMOUNTS,
> + VFS_CLOSEMOUNTS,
> +
> + VFS_OPENDIR,
> + VFS_READDIR,
> + VFS_CLOSEDIR,
> + VFS_MKDIR,
> + VFS_RMDIR,
> + VFS_REMOVE,
> + VFS_RENAME,
> + VFS_GETATTR,
> + VFS_SETATTR,
> +
> + VFS_OPENFILE,
> + VFS_CLOSEFILE,
> + VFS_WRITEFILE,
> + VFS_READFILE,
> + VFS_GETFILESIZE,
> + VFS_SETFILESIZE,
> + VFS_FILESYNC,
> +
> + VFS_SYMLINK,
> + VFS_READLINK
> +} VFSOp;
> +
> +/********************************************************************
> + * maximum _data_ transfer in a message, this must allow for
> + * other message parameters
> + * \todo it should be derived from the maximum messsage size
> + ********************************************************************/
> +#define VFS_MAX_DATA 4096
> +#define VFS_MAX_MSG 8192
> +
> +struct VFS {
> + MessageBox *mb;
> + MessageComposer *mc;
> + MessageDecomposer *md;
> +
> + int last_err;
> +};
> +
> +void vfsop_init(VFS *vfs, MessageBox *mb)
> +{
> + vfs->mb = mb;
> + vfs->mc = msgc_new(NULL, 0);
> + vfs->md = msgd_new(NULL, 0);
> +
> + vfs->last_err = 0;
> +}
> +
> +void vfsop_cleanup(VFS *vfs)
> +{
> + vfs->mb = NULL;
> + msgc_delete(vfs->mc);
> + vfs->mc = NULL;
> + msgd_delete(vfs->md);
> + vfs->md = NULL;
> +}
> +
> +VFS *vfsop_new(MessageBox *mb)
> +{
> + VFS *vfs = (VFS *) kmalloc(sizeof(struct VFS), GFP_KERNEL);
> +
> + /* vfs should check that MB is actually a VFS mb */
> +
> + vfsop_init(vfs, mb);
> +
> + return vfs;
> +}
> +
> +void vfsop_delete(VFS *vfs)
> +{
> + vfsop_cleanup(vfs);
> + kfree(vfs);
> +}
> +
> +int vfsop_startcall(VFS *vfs, uint32_t op)
> +{
> + void *buffer;
> +
> + if (mb_lock(vfs->mb) < 0)
> + return -1;
> +
> + buffer = mb_start(vfs->mb, VFS_MAX_MSG);
> +
> + msgc_init(vfs->mc, buffer, VFS_MAX_MSG);
> +
> + msgc_put_uint32(vfs->mc, 0); /* message id */
> + msgc_put_uint32(vfs->mc, op); /* vfs operation */
> +
> + return 0;
> +}
> +
> +void vfsop_call(VFS *vfs)
> +{
> + void *buffer;
> + uint32_t blen;
> + uint32_t id;
> +
> + /* int ret = */ mb_end(vfs->mb, msgc_get_size(vfs->mc));
> +
> + msgc_cleanup(vfs->mc);
> +
> + /* todo - this can currently return -1 if the thread was interrupted.
> + * we probably don't want to support interruption during the call */
> + mb_wait(vfs->mb);
> +
> + buffer = mb_receive(vfs->mb, &blen);
> +
> + msgd_init(vfs->md, buffer, blen);
> +
> + msgd_get_uint32(vfs->md, &id); /* message id inserted above */
> +
> + /* todo - check the id's match */
> +}
> +
> +void vfsop_endcall(VFS *vfs)
> +{
> + msgd_cleanup(vfs->md);
> +
> + mb_unlock(vfs->mb);
> +}
> +
> +int32_t vfsop_openmounts(VFS *vfs)
> +{
> + int32_t handle;
> +
> + vfsop_startcall(vfs, VFS_OPENMOUNTS);
> +
> + vfsop_call(vfs);
> + msgd_get_int32(vfs->md, &handle);
> +
> + vfsop_endcall(vfs);
> +
> + return handle;
> +}
> +
> +int32_t vfsop_readmounts(VFS *vfs, int32_t handle, uint32_t attr,
> + uint8_t *attrdata, uint32_t attrdatalen)
> +{
> + int32_t ret;
> +
> + vfsop_startcall(vfs, VFS_READMOUNTS);
> +
> + msgc_put_int32(vfs->mc, handle);
> + msgc_put_uint32(vfs->mc, attr);
> + msgc_put_uint32(vfs->mc, attrdatalen);
> +
> + vfsop_call(vfs);
> +
> + msgd_get_int32(vfs->md, &ret);
> + msgd_get_data(vfs->md, attrdata, &attrdatalen);
> +
> + vfsop_endcall(vfs);
> +
> + return ret;
> +}
> +
> +int32_t vfsop_closemounts(VFS *vfs, int32_t handle)
> +{
> + int32_t ret;
> +
> + ret = vfsop_startcall(vfs, VFS_READMOUNTS);
> + if (ret < 0)
> + return ret;
> +
> + msgc_put_int32(vfs->mc, handle);
> +
> + vfsop_call(vfs);
> +
> + msgd_get_int32(vfs->md, &ret);
> +
> + vfsop_endcall(vfs);
> +
> + return ret;
> +}
> +
> +int32_t vfsop_opendir(VFS *vfs, const char *dirname)
> +{
> + int32_t ret;
> +
> + vfsop_startcall(vfs, VFS_OPENDIR);
> +
> + msgc_put_cstr(vfs->mc, dirname);
> +
> + vfsop_call(vfs);
> +
> + msgd_get_int32(vfs->md, &ret);
> +
> + vfsop_endcall(vfs);
> +
> + return ret;
> +}
> +
> +int32_t vfsop_readdir(VFS *vfs, int32_t handle, uint32_t attr,
> + uint8_t *attrdata, uint32_t attrdatalen)
> +{
> + int32_t ret;
> +
> + vfsop_startcall(vfs, VFS_READDIR);
> +
> + msgc_put_int32(vfs->mc, handle);
> + msgc_put_uint32(vfs->mc, attr);
> + msgc_put_uint32(vfs->mc, attrdatalen);
> +
> + vfsop_call(vfs);
> +
> + msgd_get_int32(vfs->md, &ret);
> + msgd_get_data(vfs->md, attrdata, &attrdatalen);
> +
> + vfsop_endcall(vfs);
> +
> + return ret;
> +}
> +
> +int32_t vfsop_closedir(VFS *vfs, int32_t handle)
> +{
> + int32_t ret;
> +
> + vfsop_startcall(vfs, VFS_CLOSEDIR);
> +
> + msgc_put_int32(vfs->mc, handle);
> +
> + vfsop_call(vfs);
> +
> + msgd_get_int32(vfs->md, &ret);
> +
> + vfsop_endcall(vfs);
> +
> + return ret;
> +}
> +
> +int32_t vfsop_mkdir(VFS *vfs, const char *name)
> +{
> + int32_t ret;
> +
> + vfsop_startcall(vfs, VFS_MKDIR);
> +
> + msgc_put_cstr(vfs->mc, name);
> +
> + vfsop_call(vfs);
> +
> + msgd_get_int32(vfs->md, &ret);
> +
> + vfsop_endcall(vfs);
> +
> + return ret;
> +}
> +
> +int32_t vfsop_rmdir(VFS *vfs, const char *name)
> +{
> + int32_t ret;
> +
> + vfsop_startcall(vfs, VFS_RMDIR);
> +
> + msgc_put_cstr(vfs->mc, name);
> +
> + vfsop_call(vfs);
> +
> + msgd_get_int32(vfs->md, &ret);
> +
> + vfsop_endcall(vfs);
> +
> + return ret;
> +}
> +
> +int32_t vfsop_remove(VFS *vfs, const char *name)
> +{
> + int32_t ret;
> +
> + vfsop_startcall(vfs, VFS_REMOVE);
> +
> + msgc_put_cstr(vfs->mc, name);
> +
> + vfsop_call(vfs);
> +
> + msgd_get_int32(vfs->md, &ret);
> +
> + vfsop_endcall(vfs);
> +
> + return ret;
> +}
> +
> +int32_t vfsop_rename(VFS *vfs, const char *oldname, const char *newname)
> +{
> + int32_t ret;
> +
> + vfsop_startcall(vfs, VFS_RENAME);
> +
> + msgc_put_cstr(vfs->mc, oldname);
> + msgc_put_cstr(vfs->mc, newname);
> +
> + vfsop_call(vfs);
> +
> + msgd_get_int32(vfs->md, &ret);
> +
> + vfsop_endcall(vfs);
> +
> + return ret;
> +}
> +
> +int32_t vfsop_getattr(VFS *vfs, const char *name, uint32_t attr,
> + uint8_t *attrdata, uint32_t attrdatalen)
> +{
> + int32_t ret;
> +
> + vfsop_startcall(vfs, VFS_GETATTR);
> +
> + msgc_put_cstr(vfs->mc, name);
> + msgc_put_uint32(vfs->mc, attr);
> + msgc_put_uint32(vfs->mc, attrdatalen);
> +
> + vfsop_call(vfs);
> +
> + msgd_get_int32(vfs->md, &ret);
> + msgd_get_data(vfs->md, attrdata, &attrdatalen);
> +
> + vfsop_endcall(vfs);
> +
> + return ret;
> +}
> +
> +int32_t vfsop_setattr(VFS *vfs, const char *name, uint32_t attr,
> + const uint8_t *attrdata, uint32_t attrdatalen)
> +{
> + int32_t ret;
> +
> + vfsop_startcall(vfs, VFS_SETATTR);
> +
> + msgc_put_cstr(vfs->mc, name);
> + msgc_put_uint32(vfs->mc, attr);
> + msgc_put_data(vfs->mc, attrdata, attrdatalen);
> +
> + vfsop_call(vfs);
> +
> + msgd_get_int32(vfs->md, &ret);
> +
> + vfsop_endcall(vfs);
> +
> + return ret;
> +}
> +
> +int32_t vfsop_openfile(VFS *vfs, const char *name, uint32_t flags)
> +{
> + int32_t ret;
> +
> + vfsop_startcall(vfs, VFS_OPENFILE);
> +
> + msgc_put_cstr(vfs->mc, name);
> + msgc_put_uint32(vfs->mc, flags);
> +
> + vfsop_call(vfs);
> +
> + msgd_get_int32(vfs->md, &ret);
> +
> + vfsop_endcall(vfs);
> +
> + return ret;
> +}
> +
> +int32_t vfsop_closefile(VFS *vfs, int32_t handle)
> +{
> + int32_t ret;
> +
> + vfsop_startcall(vfs, VFS_CLOSEFILE);
> +
> + msgc_put_int32(vfs->mc, handle);
> +
> + vfsop_call(vfs);
> +
> + msgd_get_int32(vfs->md, &ret);
> +
> + vfsop_endcall(vfs);
> +
> + return ret;
> +}
> +
> +int32_t vfsop_writefile(VFS *vfs, int32_t handle, uint64_t offset,
> + const void *data, int32_t len)
> +{
> + int32_t ret;
> + int32_t residual = len;
> +
> + /* Transfer has to be broken into manageable chunks */
> +
> + while (residual > 0) {
> + int32_t t_len =
> + (residual > VFS_MAX_DATA) ? VFS_MAX_DATA : residual;
> +
> + vfsop_startcall(vfs, VFS_WRITEFILE);
> +
> + msgc_put_int32(vfs->mc, handle);
> + msgc_put_uint64(vfs->mc, offset);
> + msgc_put_data(vfs->mc, data, t_len);
> + msgc_put_uint32(vfs->mc, t_len);
> +
> + vfsop_call(vfs);
> +
> + msgd_get_int32(vfs->md, &ret);
> +
> + vfsop_endcall(vfs);
> +
> + if (ret < 0)
> + return ret;
> +
> + offset += ret;
> + residual -= ret;
> + data = (uint8_t *) data + ret;
> +
> + if (ret < t_len)
> + break;
> + }
> +
> + return len - residual;
> +}
> +
> +int32_t vfsop_readfile(VFS *vfs, int32_t handle, uint64_t offset, void *data,
> + int32_t len)
> +{
> + int32_t ret;
> + int32_t residual = len;
> + uint32_t rlen = len;
> +
> + /* data must be sent in manageable chunks */
> +
> + while (residual > 0) {
> + int32_t t_len =
> + (residual > VFS_MAX_DATA) ? VFS_MAX_DATA : residual;
> +
> + vfsop_startcall(vfs, VFS_READFILE);
> +
> + msgc_put_int32(vfs->mc, handle);
> + msgc_put_uint64(vfs->mc, offset);
> + msgc_put_uint32(vfs->mc, t_len);
> +
> + vfsop_call(vfs);
> +
> + msgd_get_int32(vfs->md, &ret);
> + msgd_get_data(vfs->md, data, &rlen);
> +
> + vfsop_endcall(vfs);
> +
> + if (ret < 0)
> + return ret;
> +
> + offset += ret;
> + residual -= ret;
> + data = (uint8_t *) data + ret;
> +
> + if (ret < t_len)
> + break;
> + }
> +
> + return len - residual;
> +}
> +
> +int32_t vfsop_getfilesize(VFS *vfs, int32_t handle, uint64_t *size)
> +{
> + int32_t ret;
> +
> + vfsop_startcall(vfs, VFS_GETFILESIZE);
> +
> + msgc_put_int32(vfs->mc, handle);
> +
> + vfsop_call(vfs);
> +
> + msgd_get_int32(vfs->md, &ret);
> + msgd_get_uint64(vfs->md, size);
> +
> + vfsop_endcall(vfs);
> +
> + return ret;
> +}
> +
> +int32_t vfsop_setfilesize(VFS *vfs, int32_t handle, uint64_t size)
> +{
> + int32_t ret;
> +
> + vfsop_startcall(vfs, VFS_SETFILESIZE);
> +
> + msgc_put_int32(vfs->mc, handle);
> + msgc_put_uint64(vfs->mc, size);
> +
> + vfsop_call(vfs);
> +
> + msgd_get_int32(vfs->md, &ret);
> +
> + vfsop_endcall(vfs);
> +
> + return ret;
> +}
> +
> +int32_t vfsop_filesync(VFS *vfs, int32_t handle)
> +{
> + int32_t ret;
> +
> + vfsop_startcall(vfs, VFS_FILESYNC);
> +
> + msgc_put_int32(vfs->mc, handle);
> +
> + vfsop_call(vfs);
> +
> + msgd_get_int32(vfs->md, &ret);
> +
> + vfsop_endcall(vfs);
> +
> + return ret;
> +}
> +
> +int32_t vfsop_symlink(VFS *vfs, const char *filename, const char *symlink)
> +{
> + int32_t ret;
> +
> + vfsop_startcall(vfs, VFS_SYMLINK);
> +
> + msgc_put_cstr(vfs->mc, filename);
> + msgc_put_cstr(vfs->mc, symlink);
> +
> + vfsop_call(vfs);
> +
> + msgd_get_int32(vfs->md, &ret);
> +
> + vfsop_endcall(vfs);
> +
> + return ret;
> +}
> +
> +int32_t vfsop_readlink(VFS *vfs, const char *filename, char *buf,
> + int32_t bufsiz)
> +{
> + int32_t ret;
> + uint32_t rlen;
> +
> + vfsop_startcall(vfs, VFS_READLINK);
> +
> + msgc_put_cstr(vfs->mc, filename);
> + msgc_put_int32(vfs->mc, bufsiz);
> +
> + vfsop_call(vfs);
> +
> + msgd_get_int32(vfs->md, &ret);
> + msgd_get_data(vfs->md, buf, &rlen);
> +
> + vfsop_endcall(vfs);
> +
> + return ret;
> +}
> diff --git a/fs/vmfs/vfs.h b/fs/vmfs/vfs.h
> new file mode 100644
> index 0000000..5e04f69
> --- /dev/null
> +++ b/fs/vmfs/vfs.h
> @@ -0,0 +1,356 @@
> +/*
> + * Copyright 2008-2009 ARM Limited. All rights reserved.
> + */
> +
> +/*!
> + * \file vfs.h
> + * \brief target side vfs interface in C
> + *
> + * This interface has been renamed to VFS (and the operations to vfsop) to
> + * avoid symbol clashes in linux. We should standardise on one or the other.
> + */
> +
> +#ifndef VFS_H
> +#define VFS_H
> +
> +#include "messagebox.h"
> +
> +/* get these definitions from a shared header used on both host/target side */
> +
> +/* Objects types that can exist on a filesystem */
> +enum VFSType {
> + VFS_TYPE_NONE, /* file not found */
> + VFS_TYPE_FILE, /* regular file */
> + VFS_TYPE_DIR, /* directory */
> + VFS_TYPE_LINK, /* symbolic link */
> + VFS_TYPE_UNKNOWN, /* unknown object type */
> + VFS_TYPE_MOUNT /* mount point */
> +};
> +
> +/* \todo these should probably be +ve and return as -VFS_ERR_ etc. */
> +enum VFSError {
> + VFS_ERR_OK = 0, /* all ok (actually 0 or +ve means ok) */
> + VFS_ERR_BADHANDLE = -1, /* invalid or wrong type of handle */
> + VFS_ERR_NOENTRY = -2, /* no more entries in a directory */
> + VFS_ERR_NOROOM = -3, /* ran out of memory/buffer/disk space */
> + VFS_ERR_MAXHANDLE = -4, /* ran out of handles */
> + VFS_ERR_NOMOUNT = -5, /* no such mount exists */
> + VFS_ERR_NOTFOUND = -6, /* object not found */
> + VFS_ERR_PERM = -7, /* permission error */
> + VFS_ERR_NOTDIR = -8, /* path element wasn't a directory */
> + VFS_ERR_TOOLONG = -9, /* path or path element too long */
> + VFS_ERR_EXIST = -10, /* an object with the name already exists */
> + VFS_ERR_NOTEMPTY = -11, /* tried to remove dir that wasn't empty */
> + VFS_ERR_INVALID = -12, /* invalid operation or operand */
> + VFS_ERR_ISDIR = -13, /* object is a directory */
> + VFS_ERR_TOOBIG = -14, /* return value too large to represent */
> + VFS_ERR_UNIMPL = -15, /* unimplemented feature */
> + VFS_ERR_UNKNOWN = -100 /* unexpected host error */
> +};
> +
> +typedef enum VFSAttr {
> + VFS_ATTR_MTIME = 0x0001, /* uint64_t modification time */
> + VFS_ATTR_ACCESS = 0x0002, /* uint32_t access permissions (r/w/e) */
> + VFS_ATTR_TYPE = 0x0004, /* uint32_t obj type (as above) */
> + VFS_ATTR_SIZE = 0x0008, /* uint64_t obj size in bytes */
> + VFS_ATTR_CTIME = 0x0010, /* uint64_t obj creation time */
> + VFS_ATTR_ATIME = 0x0020, /* uint64_t obj access time */
> + VFS_ATTR_RTIME = 0x0040, /* uint64_t current real time */
> + VFS_ATTR_DISKSIZE = 0x0100, /* uint64_t size of disk in bytes */
> + VFS_ATTR_DISKFREE = 0x0200, /* uint64_t free space on disk in bytes */
> + VFS_ATTR_NAME = 0x8000, /* char* last to make variable length easy */
> +} VFSAttr;
> +
> +/* flags passed to Mount::openFile */
> +typedef enum VFSOpenFlags {
> + VFS_OPEN_RDONLY = 1,
> + VFS_OPEN_WRONLY = 2,
> + VFS_OPEN_RDWR = VFS_OPEN_RDONLY | VFS_OPEN_WRONLY,
> + VFS_OPEN_CREATE = 4,
> + VFS_OPEN_NEW = 8,
> + VFS_OPEN_TRUNCATE = 16
> +} VFSOpenFlags;
> +
> +/*! Opaque instance handle for use in vfs calls */
> +typedef struct VFS VFS;
> +
> + /*! instantiate a new vfs object
> + *
> + * \param mb message box instance to use as a transport layer
> + *
> + * \return vfs instance handle to use in vfs calls
> + */
> +VFS *vfsop_new(MessageBox *mb);
> +
> + /*! delete a vfs instance
> + *
> + * \param vfs instance to delete
> + */
> +void vfsop_delete(VFS *vfs);
> +
> + /*! Open an iterator on the list of mounts added with add Mount
> + *
> + * \param vfs vfs instance
> + *
> + * \return a handle to be used with readmounts/closemounts or VFSError code
> + */
> +int32_t vfsop_openmounts(VFS *vfs);
> +
> + /* Read the next entry in a list of mounts
> + *
> + * \param vfs vfs instance
> + * \param id mount iterator handle
> + * \param attr bit mask of attributes to return (one or more VFSAttr)
> + * \param attrdata data block to receive attributes
> + * \param attrlen size of attribute block
> + *
> + * \return VFSError code
> + *
> + * The attribute block is packed with data in VFSAttr order (lowest to
> + * highest). Be careful to unpack the attribute block using the correct
> + * data sizes. Not all attributes are relavent to mount data
> + *
> + */
> +int32_t vfsop_readmounts(VFS *vfs, int32_t handle, uint32_t attr,
> + uint8_t *attrdata, uint32_t attrdatalen);
> +
> + /* Close a mount iterator handle
> + *
> + * \param vfs vfs instance
> + * \param id mount iterator handle
> + *
> + * \return VFSError code
> + */
> +int32_t vfsop_closemounts(VFS *vfs, int32_t handle);
> +
> + /* Open a directory iterator handle
> + *
> + * \param vfs vfs instance
> + * \param name full (vfs) path name to directory
> + *
> + * \return directory iterator handle for use with readdir/closedir
> + * or a VFSError code
> + */
> +int32_t vfsop_opendir(VFS *vfs, const char *dirname);
> +
> + /* Read an entry form a directory iterator
> + *
> + * \param vfs vfs instance
> + * \param id directory iterator handle
> + * \param attr bit mask of attributes to return (one or more VFSAttr)
> + * \param attrdata data block to receive attributes
> + * \param attrlen size of attribute block
> + *
> + * \return VFSError code
> + *
> + * The attribute block is packed with data in VFSAttr order (lowest to
> + * highest). Be careful to unpack the attribute block using the correct
> + * data sizes
> + *
> + * \todo pass attrlen by reference so it can be updated with the size used
> + * \todo pass attr by reference so that the actual returned attributes can
> + * be indicated
> + */
> +int32_t vfsop_readdir(VFS *vfs, int32_t handle, uint32_t attr,
> + uint8_t *attrdata, uint32_t attrdatalen);
> +
> + /* Close a directory iterator
> + *
> + * \param vfs vfs instance
> + * \param id directory iterator handle
> + *
> + * \return VFSError code
> + */
> +int32_t vfsop_closedir(VFS *vfs, int32_t handle);
> +
> + /* Create a directory
> + *
> + * \param vfs vfs instance
> + * \param name (vfs) directory name to create
> + *
> + * \return VFSError code
> + */
> +int32_t vfsop_mkdir(VFS *vfs, const char *name);
> +
> + /* Remove a directory
> + *
> + * \param vfs vfs instance
> + * \param name (vfs) directory name to create
> + *
> + * \return VFSError code
> + */
> +int32_t vfsop_rmdir(VFS *vfs, const char *name);
> +
> + /* Remove a file
> + *
> + * \param vfs vfs instance
> + * \param name (vfs) file to remove (may also work on other
> + * object types)
> + *
> + * \return VFSError code
> + */
> +int32_t vfsop_remove(VFS *vfs, const char *name);
> +
> + /* Rename an object
> + *
> + * \param vfs vfs instance
> + * \param oldname (vfs) object to rename
> + * \param newname (vfs) new name of object
> + *
> + * \return VFSError code
> + */
> +int32_t vfsop_rename(VFS *vfs, const char *oldname, const char *newname);
> +
> + /* Retrieve attributes of an object on the filesystem
> + *
> + * \param vfs vfs instance
> + * \param name (vfs) object name
> + * \param attr bit mask of attributes to return (one or more VFSAttr)
> + * \param attrdata data block to receive attributes
> + * \param attrlen size of attribute block
> + *
> + * \return VFSError code
> + *
> + * The attribute block is packed with data in VFSAttr order (lowest to
> + * highest). Be careful to unpack the attribute block using the
> + * correct data sizes
> + *
> + * \todo pass attrlen by reference so it can be updated with the size used
> + * \todo pass attr by reference so that the actual returned attributes
> + * can be indicated
> + */
> +int32_t vfsop_getattr(VFS *vfs, const char *name, uint32_t attr,
> + uint8_t *attrdata, uint32_t attrdatalen);
> +
> + /* Retrieve attributes of an object on the filesystem
> + *
> + * \param vfs vfs instance
> + * \param name (vfs) object name
> + * \param attr bit mask of attributes to modify (one or more VFSAttr)
> + * \param attrdata data block containing packed attributes
> + * \param attrlen size of attribute block
> + *
> + * \return VFSError code
> + *
> + * The attribute block should be packed with data in VFSAttr order
> + * (lowest to highest). Be careful to pack the attribute block using
> + * the correct data sizes
> + *
> + * Not all attributes can be modified using this (e.g. file size/disk
> + * free/file name)
> + *
> + * \todo pass attr by reference so that the actual modified
> + * attributes can be indicated
> + */
> +int32_t vfsop_setattr(VFS *vfs, const char *name, uint32_t attr,
> + const uint8_t *attrdata, uint32_t attrdatalen);
> +
> + /* Open a file object on the filesystem for reading/writing
> + *
> + * \param vfs vfs instance
> + * \param filename (vfs) file name
> + * \param flags VFSOpenFlags value indicating how to open the file
> + *
> + * \return file handle to use with readfile/writefile/closefile etc or
> + * a VFSError code
> + */
> +int32_t vfsop_openfile(VFS *vfs, const char *name, uint32_t flags);
> +
> + /* Close a file object by a handle returned from openfile
> + *
> + * \param vfs vfs instance
> + * \param id file handle
> + *
> + * \return VFSError code
> + */
> +int32_t vfsop_closefile(VFS *vfs, int32_t handle);
> +
> + /* Write data to a file
> + *
> + * \param vfs vfs instance
> + * \param id file handle returned from openfile
> + * \param offset offset into file from where to start writing
> + * \param data pointer to data block containing data to be written
> + * \param len length of data to be written
> + *
> + * \return length of data actually written to the file or a VFSError code
> + */
> +int32_t vfsop_writefile(VFS *vfs, int32_t handle, uint64_t offset,
> + const void *data, int32_t len);
> +
> + /* Read data from a file
> + *
> + * \param vfs vfs instance
> + * \param id file handle returned from openfile
> + * \param offset offset into file from where to start reading
> + * \param data pointer to data block to receive data read from file
> + * \param len size of data block to receive data
> + *
> + * \return length of data actually read from the file or a VFSError code
> + */
> +int32_t vfsop_readfile(VFS *vfs, int32_t handle, uint64_t offset, void *data,
> + int32_t len);
> +
> + /* Get the size of an open file
> + *
> + * \param vfs vfs instance
> + * \param id file handle returned from openfile
> + * \param size pointer to instance data to receive file size
> + *
> + * \return VFSError code
> + */
> +int32_t vfsop_getfilesize(VFS *vfs, int32_t handle, uint64_t *size);
> +
> + /* Set the size of an open file
> + *
> + * \param vfs vfs instance
> + * \param id file handle returned from openfile
> + * \param size new size of file
> + *
> + * \return VFSError code
> + *
> + * this will truncate or extend the file depending on whether the new
> + * size is smaller or larger than the current file size
> + */
> +int32_t vfsop_setfilesize(VFS *vfs, int32_t handle, uint64_t size);
> +
> + /* Force modified parts of a file back to persistent storage
> + *
> + * \param vfs vfs instance
> + * \param id file handle returned from openfile
> + *
> + * \return VFSError code
> + */
> +int32_t vfsop_filesync(VFS *vfs, int32_t handle);
> +
> +/* Linux target support functions */
> +
> + /* Create a symbolic link object
> + *
> + * \param vfs vfs instance
> + * \param filename (vfs) name of link object to be created
> + * \param data content of link object (typically a path to
> + * another object)
> + *
> + * \return VFSError code
> + *
> + * \todo this is not yet implemented
> + */
> +
> +int32_t vfsop_symlink(VFS *vfs, const char *filename, const char *symlink);
> +
> + /* Read the contents of a symbolic link object
> + *
> + * \param vfs vfs instance
> + * \param filename (vfs) name of link object to be read
> + * \param data data block to receive link object contents
> + * \param bufsiz size of data block to receive link object contents
> + *
> + * \return VFSError code
> + *
> + * \todo this is not yet implemented
> + */
> +int32_t vfsop_readlink(VFS *vfs, const char *filename, char *buf,
> + int32_t bufsiz);
> +
> +#endif /* VFS_H */
> diff --git a/fs/vmfs/vmfs.h b/fs/vmfs/vmfs.h
> new file mode 100644
> index 0000000..82a5c64
> --- /dev/null
> +++ b/fs/vmfs/vmfs.h
> @@ -0,0 +1,44 @@
> +/*
> + * vmfs.h
> + *
> + * Copyright (C) 1995, 1996 by Paal-Kr. Engstad and Volker Lendecke
> + * Copyright (C) 1997 by Volker Lendecke
> + *
> + */
> +
> +#ifndef _LINUX_VMFS_H
> +#define _LINUX_VMFS_H
> +
> +#include <linux/types.h>
> +#include <linux/magic.h>
> +
> +#ifdef __KERNEL__
> +
> +#define VMFS_MAXNAMELEN 255
> +#define VMFS_MAXPATHLEN 1024
> +
> +/*
> + * Contains all relevant data on a VMFS networked file.
> + */
> +struct vmfs_fattr {
> + __u16 attr;
> +
> + unsigned long f_ino;
> + umode_t f_mode;
> + nlink_t f_nlink;
> + uid_t f_uid;
> + gid_t f_gid;
> + dev_t f_rdev;
> + loff_t f_size;
> + struct timespec f_atime;
> + struct timespec f_mtime;
> + struct timespec f_ctime;
> + unsigned long f_blocks;
> + int f_unix;
> +
> + /* vfs bits */
> + uint32_t f_type;
> +};
> +
> +#endif
> +#endif
> diff --git a/fs/vmfs/vmfs_debug.h b/fs/vmfs/vmfs_debug.h
> new file mode 100644
> index 0000000..b9ba4d3
> --- /dev/null
> +++ b/fs/vmfs/vmfs_debug.h
> @@ -0,0 +1,39 @@
> +/*
> + * Defines some debug macros for vmfs_.
> + */
> +
> +/* This makes a dentry parent/child name pair. Useful for debugging printk's */
> +#define DENTRY_PATH(dentry) \
> + ((dentry)->d_parent->d_name.name, (dentry)->d_name.name)
> +
> +/*
> + * safety checks that should never happen ???
> + * these are normally enabled.
> + */
> +#ifdef VMFSFS_PARANOIA
> +#define PARANOIA(f, a...) printk(KERN_NOTICE "%s: " f, __func__ , ## a)
> +#else
> +#define PARANOIA(f, a...) do { ; } while (0)
> +#endif
> +
> +/* lots of debug messages */
> +#ifdef VMFSFS_DEBUG_VERBOSE
> +#define VERBOSE(f, a...) printk(KERN_DEBUG "%s: " f, __func__ , ## a)
> +#else
> +#define VERBOSE(f, a...) do { ; } while (0)
> +#endif
> +
> +/*
> + * "normal" debug messages, but not with a normal DEBUG define ... way
> + * too common name.
> + */
> +#ifdef VMFSFS_DEBUG
> +#define DEBUG1(f, a...) printk(KERN_DEBUG "%s: " f, __func__ , ## a)
> +#define FNENTER(f, a...) printk(KERN_DEBUG "enter %s:\n" f, \
> + __func__ , ## a)
> +#define FNEXIT(f, a...) printk(KERN_DEBUG "exit %s:\n" f, __func__ , ## a)
> +#else
> +#define DEBUG1(f, a...) do { ; } while (0)
> +#define FNENTER(f, a...) do { ; } while (0)
> +#define FNEXIT(f, a...) do { ; } while (0)
> +#endif
> diff --git a/fs/vmfs/vmfs_fs.h b/fs/vmfs/vmfs_fs.h
> new file mode 100644
> index 0000000..73c88aa
> --- /dev/null
> +++ b/fs/vmfs/vmfs_fs.h
> @@ -0,0 +1,111 @@
> +/*
> + * vmfs_fs.h
> + *
> + * Copyright (C) 1995 by Paal-Kr. Engstad and Volker Lendecke
> + * Copyright (C) 1997 by Volker Lendecke
> + *
> + * Copyright (C) 2008-2009 ARM Limited
> + */
> +
> +#ifndef _LINUX_VMFS_FS_H
> +#define _LINUX_VMFS_FS_H
> +
> +#include "vmfs.h"
> +
> +/*
> + * ioctl commands
> + */
> +#define VMFS_IOC_GETMOUNTUID _IOR('u', 1, __kernel_old_uid_t)
> +
> +/* __kernel_uid_t can never change, so we have to use __kernel_uid32_t */
> +#define VMFS_IOC_GETMOUNTUID32 _IOR('u', 3, __kernel_uid32_t)
> +
> +#ifdef __KERNEL__
> +#include "vmfs_fs_i.h"
> +#include "vmfs_fs_sb.h"
> +
> +#include <linux/fs.h>
> +#include <linux/pagemap.h>
> +#include <linux/vmalloc.h>
> +#include "vmfs_mount.h"
> +#include <linux/jiffies.h>
> +#include <asm/unaligned.h>
> +
> +static inline struct vmfs_sb_info *VMFS_SB(struct super_block *sb)
> +{
> + return sb->s_fs_info;
> +}
> +
> +static inline struct vmfs_inode_info *VMFS_I(struct inode *inode)
> +{
> + return container_of(inode, struct vmfs_inode_info, vfs_inode);
> +}
> +
> +/*
> + * This is the time we allow an inode, dentry or dir cache to live. It is bad
> + * for performance to have shorter ttl on an inode than on the cache. It can
> + * cause refresh on each inode for a dir listing ... one-by-one
> + */
> +#define VMFS_MAX_AGE(server) (((server)->mnt->ttl * HZ) / 1000)
> +
> +static inline void
> +vmfs_age_dentry(struct vmfs_sb_info *server, struct dentry *dentry)
> +{
> + dentry->d_time = jiffies - VMFS_MAX_AGE(server);
> +}
> +
> +struct vmfs_cache_head {
> + time_t mtime; /* unused */
> + unsigned long time; /* cache age */
> + unsigned long end; /* last valid fpos in cache */
> + int eof;
> +};
> +
> +#define VMFS_DIRCACHE_SIZE ((int)(PAGE_CACHE_SIZE/sizeof(struct dentry *)))
> +union vmfs_dir_cache {
> + struct vmfs_cache_head head;
> + struct dentry *dentry[VMFS_DIRCACHE_SIZE];
> +};
> +
> +#define VMFS_FIRSTCACHE_SIZE ((int)((VMFS_DIRCACHE_SIZE * \
> + sizeof(struct dentry *) - sizeof(struct vmfs_cache_head)) / \
> + sizeof(struct dentry *)))
> +
> +#define VMFS_DIRCACHE_START (VMFS_DIRCACHE_SIZE - VMFS_FIRSTCACHE_SIZE)
> +
> +struct vmfs_cache_control {
> + struct vmfs_cache_head head;
> + struct page *page;
> + union vmfs_dir_cache *cache;
> + unsigned long fpos, ofs;
> + int filled, valid, idx;
> +};
> +
> +#define VMFS_OPS_NUM_STATIC 5
> +struct vmfs_ops {
> + int (*read) (struct inode *inode, loff_t offset, int count,
> + char *data);
> + int (*write) (struct inode *inode, loff_t offset, int count, const
> + char *data);
> + int (*readdir) (struct file *filp, void *dirent, filldir_t filldir,
> + struct vmfs_cache_control *ctl);
> +
> + int (*getattr) (struct vmfs_sb_info *server, struct dentry *dir,
> + struct vmfs_fattr *fattr);
> + /* int (*setattr)(...); *//* setattr is really icky! */
> +
> + int (*truncate) (struct inode *inode, loff_t length);
> +};
> +
> +static inline int vmfs_is_open(struct inode *i)
> +{
> + return (VMFS_I(i)->vopen == 1);
> +}
> +
> +extern void vmfs_install_ops(struct vmfs_ops *);
> +
> +extern struct mutex vmfs_mutex;
> +
> +#endif /* __KERNEL__ */
> +
> +#endif /* _LINUX_VMFS_FS_H */
> diff --git a/fs/vmfs/vmfs_fs_i.h b/fs/vmfs/vmfs_fs_i.h
> new file mode 100644
> index 0000000..34f0028
> --- /dev/null
> +++ b/fs/vmfs/vmfs_fs_i.h
> @@ -0,0 +1,39 @@
> +/*
> + * vmfs_fs_i.h
> + *
> + * Copyright (C) 1995 by Paal-Kr. Engstad and Volker Lendecke
> + * Copyright (C) 1997 by Volker Lendecke
> + *
> + */
> +
> +#ifndef _LINUX_VMFS_FS_I
> +#define _LINUX_VMFS_FS_I
> +
> +#ifdef __KERNEL__
> +#include <linux/types.h>
> +#include <linux/fs.h>
> +
> +/*
> + * vmfs fs inode data (in memory only)
> + */
> +struct vmfs_inode_info {
> +
> + unsigned int open; /* open generation */
> +
> + unsigned long oldmtime; /* last time refreshed */
> + unsigned long closed; /* timestamp when closed */
> + unsigned openers; /* number of fileid users */
> +
> + /* GPB - vfs data - we also use access */
> +
> + uint32_t vhandle; /* host side handle */
> + uint32_t vaccess; /* access (VMFS_OPEN_ ) */
> + uint32_t vopen; /* set to 1 when the file is open
> + (why not use openers?) */
> +
> + struct inode vfs_inode; /* must be at the end */
> +
> +};
> +
> +#endif
> +#endif
> diff --git a/fs/vmfs/vmfs_fs_sb.h b/fs/vmfs/vmfs_fs_sb.h
> new file mode 100644
> index 0000000..f98e35d
> --- /dev/null
> +++ b/fs/vmfs/vmfs_fs_sb.h
> @@ -0,0 +1,64 @@
> +/*
> + * vmfs_fs_sb.h
> + *
> + * Copyright (C) 1995 by Paal-Kr. Engstad and Volker Lendecke
> + * Copyright (C) 1997 by Volker Lendecke
> + *
> + * Copyright (C) 2008-2009 ARM Limited
> + *
> + */
> +
> +#ifndef _VMFS_FS_SB
> +#define _VMFS_FS_SB
> +
> +#ifdef __KERNEL__
> +
> +#include <linux/types.h>
> +#include "vmfs.h"
> +#include "vfs.h"
> +
> +/* structure access macros */
> +#define server_from_inode(inode) VMFS_SB((inode)->i_sb)
> +#define server_from_dentry(dentry) VMFS_SB((dentry)->d_sb)
> +#define SB_of(server) ((server)->super_block)
> +
> +struct vmfs_sb_info {
> + /* List of all vmfsfs superblocks */
> + struct list_head entry;
> +
> + /* GPBTODO - most of the 'server' code here should move to the
> + * messagebox
> + */
> +
> + struct vmfs_mount_data_kernel *mnt;
> +
> + /* Connections are counted. Each time a new socket arrives,
> + * generation is incremented.
> + */
> + struct semaphore sem;
> +
> + struct vmfs_ops *ops;
> +
> + struct super_block *super_block;
> +
> + VFS *vfs;
> +};
> +
> +static inline int vmfs_lock_server_interruptible(struct vmfs_sb_info *server)
> +{
> + return down_interruptible(&(server->sem));
> +}
> +
> +static inline void vmfs_lock_server(struct vmfs_sb_info *server)
> +{
> + down(&(server->sem));
> +}
> +
> +static inline void vmfs_unlock_server(struct vmfs_sb_info *server)
> +{
> + up(&(server->sem));
> +}
> +
> +#endif /* __KERNEL__ */
> +
> +#endif
> diff --git a/fs/vmfs/vmfs_mount.h b/fs/vmfs/vmfs_mount.h
> new file mode 100644
> index 0000000..2dc784d
> --- /dev/null
> +++ b/fs/vmfs/vmfs_mount.h
> @@ -0,0 +1,62 @@
> +/*
> + * vmfs_mount.h
> + *
> + * Copyright (C) 1995, 1996 by Paal-Kr. Engstad and Volker Lendecke
> + * Copyright (C) 1997 by Volker Lendecke
> + *
> + */
> +
> +#ifndef _LINUX_VMFS_MOUNT_H
> +#define _LINUX_VMFS_MOUNT_H
> +
> +#include <linux/types.h>
> +
> +#define VMFS_MOUNT_VERSION 6
> +
> +struct vmfs_mount_data {
> + int version;
> + __kernel_uid_t mounted_uid; /* Who may umount() this filesystem? */
> + __kernel_uid_t uid;
> + __kernel_gid_t gid;
> + __kernel_mode_t file_mode;
> + __kernel_mode_t dir_mode;
> +};
> +
> +#ifdef __KERNEL__
> +
> +/* "vers" in big-endian */
> +#define VMFS_MOUNT_ASCII 0x76657273
> +
> +#define VMFS_MOUNT_OLDVERSION 6
> +#undef VMFS_MOUNT_VERSION
> +#define VMFS_MOUNT_VERSION 7
> +
> +/* flags */
> +#define VMFS_MOUNT_WIN95 0x0001 /* Win 95 server */
> +#define VMFS_MOUNT_OLDATTR 0x0002 /* Use core getattr (Win 95 speedup) */
> +#define VMFS_MOUNT_DIRATTR 0x0004 /* Use find_first for getattr */
> +#define VMFS_MOUNT_CASE 0x0008 /* Be case sensitive */
> +#define VMFS_MOUNT_UNICODE 0x0010 /* Server talks unicode */
> +#define VMFS_MOUNT_UID 0x0020 /* Use user specified uid */
> +#define VMFS_MOUNT_GID 0x0040 /* Use user specified gid */
> +#define VMFS_MOUNT_FMODE 0x0080 /* Use user specified file mode */
> +#define VMFS_MOUNT_DMODE 0x0100 /* Use user specified dir mode */
> +
> +struct vmfs_mount_data_kernel {
> + int version;
> +
> + uid_t mounted_uid; /* Who may umount() this filesystem? */
> + uid_t uid;
> + gid_t gid;
> + mode_t file_mode;
> + mode_t dir_mode;
> +
> + u32 flags;
> +
> + /* maximum age in jiffies (inode, dentry and dircache) */
> + int ttl;
> +};
> +
> +#endif
> +
> +#endif
> diff --git a/fs/vmfs/vmfsno.h b/fs/vmfs/vmfsno.h
> new file mode 100644
> index 0000000..b2734cc
> --- /dev/null
> +++ b/fs/vmfs/vmfsno.h
> @@ -0,0 +1,138 @@
> +#ifndef _VMFSNO_H_
> +#define _VMFSNO_H_
> +
> +/* these define the attribute byte as seen by DOS */
> +#define aRONLY (1L<<0)
> +#define aHIDDEN (1L<<1)
> +#define aSYSTEM (1L<<2)
> +#define aVOLID (1L<<3)
> +#define aDIR (1L<<4)
> +#define aARCH (1L<<5)
> +
> +/* error classes */
> +#define SUCCESS 0 /* The request was successful. */
> +#define ERRDOS 0x01 /* Error is from the core DOS operating
> + * system set. */
> +#define ERRSRV 0x02 /* Error is generated by the server network
> + * file manager. */
> +#define ERRHRD 0x03 /* Error is an hardware error. */
> +#define ERRCMD 0xFF /* Command was not in the "VMFS" format. */
> +
> +/* VMFS X/Open error codes for the ERRdos error class */
> +
> +#define ERRbadfunc 1 /* Invalid function (or system call) */
> +#define ERRbadfile 2 /* File not found (pathname error) */
> +#define ERRbadpath 3 /* Directory not found */
> +#define ERRnofids 4 /* Too many open files */
> +#define ERRnoaccess 5 /* Access denied */
> +#define ERRbadfid 6 /* Invalid fid */
> +#define ERRbadmcb 7 /* Memory control blocks destroyed */
> +#define ERRnomem 8 /* Out of memory */
> +#define ERRbadmem 9 /* Invalid memory block address */
> +#define ERRbadenv 10 /* Invalid environment */
> +#define ERRbadformat 11 /* Invalid format */
> +#define ERRbadaccess 12 /* Invalid open mode */
> +#define ERRbaddata 13 /* Invalid data (only from ioctl call) */
> +#define ERRres 14 /* reserved */
> +#define ERRbaddrive 15 /* Invalid drive */
> +#define ERRremcd 16 /* Attempt to delete current directory */
> +#define ERRdiffdevice 17 /* rename/move across different filesystems */
> +#define ERRnofiles 18 /* no more files found in file search */
> +#define ERRbadshare 32 /* Share mode on file conflicts
> + * with open mode */
> +#define ERRlock 33 /* Lock request conflicts with existing lock */
> +#define ERRfilexists 80 /* File in operation already exists */
> +#define ERRbadpipe 230 /* Named pipe invalid */
> +#define ERRpipebusy 231 /* All instances of pipe are busy */
> +#define ERRpipeclosing 232 /* named pipe close in progress */
> +#define ERRnotconnected 233 /* No process on other end of named pipe */
> +#define ERRmoredata 234 /* More data to be returned */
> +
> +#define ERROR_INVALID_PARAMETER 87
> +#define ERROR_DISK_FULL 112
> +#define ERROR_INVALID_NAME 123
> +#define ERROR_DIR_NOT_EMPTY 145
> +#define ERROR_NOT_LOCKED 158
> +#define ERROR_ALREADY_EXISTS 183 /* see also 80 ? */
> +#define ERROR_EAS_DIDNT_FIT 275 /* Extended attributes didn't fit */
> +#define ERROR_EAS_NOT_SUPPORTED 282 /* Extended attributes not supported */
> +
> +/* Error codes for the ERRSRV class */
> +
> +#define ERRerror 1 /* Non specific error code */
> +#define ERRbadpw 2 /* Bad password */
> +#define ERRbadtype 3 /* reserved */
> +#define ERRaccess 4 /* No permissions to do requested operation */
> +#define ERRinvnid 5 /* tid invalid */
> +#define ERRinvnetname 6 /* Invalid servername */
> +#define ERRinvdevice 7 /* Invalid device */
> +#define ERRqfull 49 /* Print queue full */
> +#define ERRqtoobig 50 /* Queued item too big */
> +#define ERRinvpfid 52 /* Invalid print file in vmfs_fid */
> +#define ERRvmfscmd 64 /* Unrecognised command */
> +#define ERRsrverror 65 /* vmfs server internal error */
> +#define ERRfilespecs 67 /* fid and pathname invalid combination */
> +#define ERRbadlink 68 /* reserved */
> +#define ERRbadpermits 69 /* Access specified for a file is not valid */
> +#define ERRbadpid 70 /* reserved */
> +#define ERRsetattrmode 71 /* attribute mode invalid */
> +#define ERRpaused 81 /* Message server paused */
> +#define ERRmsgoff 82 /* Not receiving messages */
> +#define ERRnoroom 83 /* No room for message */
> +#define ERRrmuns 87 /* too many remote usernames */
> +#define ERRtimeout 88 /* operation timed out */
> +#define ERRnoresource 89 /* No resources currently avail for request.*/
> +#define ERRtoomanyuids 90 /* too many userids */
> +#define ERRbaduid 91 /* bad userid */
> +#define ERRuseMPX 250 /* temp unable to use raw mode, use MPX mode */
> +#define ERRuseSTD 251 /* temp unable to use raw mode, use std.mode */
> +#define ERRcontMPX 252 /* resume MPX mode */
> +#define ERRbadPW /* reserved */
> +#define ERRnosupport 0xFFFF
> +
> +/* Error codes for the ERRHRD class */
> +
> +#define ERRnowrite 19 /* read only media */
> +#define ERRbadunit 20 /* Unknown device */
> +#define ERRnotready 21 /* Drive not ready */
> +#define ERRbadcmd 22 /* Unknown command */
> +#define ERRdata 23 /* Data (CRC) error */
> +#define ERRbadreq 24 /* Bad request structure length */
> +#define ERRseek 25
> +#define ERRbadmedia 26
> +#define ERRbadsector 27
> +#define ERRnopaper 28
> +#define ERRwrite 29 /* write fault */
> +#define ERRread 30 /* read fault */
> +#define ERRgeneral 31 /* General hardware failure */
> +#define ERRwrongdisk 34
> +#define ERRFCBunavail 35
> +#define ERRsharebufexc 36 /* share buffer exceeded */
> +#define ERRdiskfull 39
> +
> +/*
> + * Access modes when opening a file
> + */
> +#define VMFS_ACCMASK 0x0003
> +#define VMFS_O_RDONLY 0x0000
> +#define VMFS_O_WRONLY 0x0001
> +#define VMFS_O_RDWR 0x0002
> +
> +/* values which means "don't change it" */
> +#define VMFS_MODE_NO_CHANGE 0xFFFFFFFF
> +#define VMFS_UID_NO_CHANGE 0xFFFFFFFF
> +#define VMFS_GID_NO_CHANGE 0xFFFFFFFF
> +#define VMFS_TIME_NO_CHANGE 0xFFFFFFFFFFFFFFFFULL
> +#define VMFS_SIZE_NO_CHANGE 0xFFFFFFFFFFFFFFFFULL
> +
> +/* UNIX filetype mappings. */
> +#define UNIX_TYPE_FILE 0
> +#define UNIX_TYPE_DIR 1
> +#define UNIX_TYPE_SYMLINK 2
> +#define UNIX_TYPE_CHARDEV 3
> +#define UNIX_TYPE_BLKDEV 4
> +#define UNIX_TYPE_FIFO 5
> +#define UNIX_TYPE_SOCKET 6
> +#define UNIX_TYPE_UNKNOWN 0xFFFFFFFF
> +
> +#endif /* _VMFSNO_H_ */
>
More information about the linux-yocto
mailing list