lkml.org 
[lkml]   [2012]   [Dec]   [5]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Subject[PATCH v2 44/44] fs: imgdafs: Add IMG DAFS filesystem for metag
    Date
    Add the IMG Debug Adapter File System (DAFS) for metag, which uses
    SWITCH operations to communicate with a file server on a host computer
    via a JTAG debug adapter.

    Signed-off-by: James Hogan <james.hogan@imgtec.com>
    Cc: Alexander Viro <viro@zeniv.linux.org.uk>
    Cc: linux-fsdevel@vger.kernel.org
    ---
    MAINTAINERS | 1 +
    arch/metag/Kconfig | 1 +
    fs/Kconfig | 1 +
    fs/Makefile | 1 +
    fs/imgdafs/Kconfig | 6 +
    fs/imgdafs/Makefile | 7 +
    fs/imgdafs/imgdafs.h | 80 +++++
    fs/imgdafs/inode.c | 840 ++++++++++++++++++++++++++++++++++++++++++++++++++
    8 files changed, 937 insertions(+), 0 deletions(-)
    create mode 100644 fs/imgdafs/Kconfig
    create mode 100644 fs/imgdafs/Makefile
    create mode 100644 fs/imgdafs/imgdafs.h
    create mode 100644 fs/imgdafs/inode.c

    diff --git a/MAINTAINERS b/MAINTAINERS
    index 9ed766d..07294e0 100644
    --- a/MAINTAINERS
    +++ b/MAINTAINERS
    @@ -4857,6 +4857,7 @@ F: arch/metag/
    F: Documentation/metag/
    F: Documentation/devicetree/bindings/metag/
    F: drivers/tty/metag_da.c
    +F: fs/imgdafs/

    MICROBLAZE ARCHITECTURE
    M: Michal Simek <monstr@monstr.eu>
    diff --git a/arch/metag/Kconfig b/arch/metag/Kconfig
    index 9489431..29787c8 100644
    --- a/arch/metag/Kconfig
    +++ b/arch/metag/Kconfig
    @@ -223,6 +223,7 @@ config METAG_DA
    This enables support for services provided by DA JTAG debug adapters,
    such as:
    - communication over DA channels (such as the console driver).
    + - use of the DA filesystem.

    menu "Boot options"

    diff --git a/fs/Kconfig b/fs/Kconfig
    index f95ae3a..b2d09b0 100644
    --- a/fs/Kconfig
    +++ b/fs/Kconfig
    @@ -220,6 +220,7 @@ source "fs/pstore/Kconfig"
    source "fs/sysv/Kconfig"
    source "fs/ufs/Kconfig"
    source "fs/exofs/Kconfig"
    +source "fs/imgdafs/Kconfig"

    endif # MISC_FILESYSTEMS

    diff --git a/fs/Makefile b/fs/Makefile
    index 1d7af79..7b478a5 100644
    --- a/fs/Makefile
    +++ b/fs/Makefile
    @@ -126,3 +126,4 @@ obj-$(CONFIG_GFS2_FS) += gfs2/
    obj-y += exofs/ # Multiple modules
    obj-$(CONFIG_CEPH_FS) += ceph/
    obj-$(CONFIG_PSTORE) += pstore/
    +obj-$(CONFIG_IMGDAFS_FS) += imgdafs/
    diff --git a/fs/imgdafs/Kconfig b/fs/imgdafs/Kconfig
    new file mode 100644
    index 0000000..5293adb
    --- /dev/null
    +++ b/fs/imgdafs/Kconfig
    @@ -0,0 +1,6 @@
    +config IMGDAFS_FS
    + bool "Meta DA filesystem support"
    + depends on METAG_DA
    + help
    + This enables the DA filesystem, which allows Linux to
    + to access files on a system attached via a debug adapter.
    diff --git a/fs/imgdafs/Makefile b/fs/imgdafs/Makefile
    new file mode 100644
    index 0000000..169a3c6
    --- /dev/null
    +++ b/fs/imgdafs/Makefile
    @@ -0,0 +1,7 @@
    +#
    +# Makefile for DAfs the Debug Adapter filesystem.
    +#
    +
    +obj-$(CONFIG_IMGDAFS_FS) += imgdafs.o
    +
    +imgdafs-objs := inode.o
    diff --git a/fs/imgdafs/imgdafs.h b/fs/imgdafs/imgdafs.h
    new file mode 100644
    index 0000000..6c1da13
    --- /dev/null
    +++ b/fs/imgdafs/imgdafs.h
    @@ -0,0 +1,80 @@
    +#ifndef _IMGDAFS_H_
    +#define _IMGDAFS_H_
    +
    +#define DA_OP_OPEN 0
    +#define DA_OP_CREAT 1
    +#define DA_OP_READ 2
    +#define DA_OP_WRITE 3
    +#define DA_OP_CLOSE 4
    +#define DA_OP_LINK 5
    +#define DA_OP_LSEEK 6
    +#define DA_OP_UNLINK 7
    +#define DA_OP_ISATTY 8
    +#define DA_OP_FCNTL 9
    +#define DA_OP_STAT 10
    +#define DA_OP_FSTAT 11
    +#define DA_OP_GETCWD 12
    +#define DA_OP_CHDIR 13
    +#define DA_OP_MKDIR 14
    +#define DA_OP_RMDIR 15
    +#define DA_OP_FINDFIRST 16
    +#define DA_OP_FINDNEXT 17
    +#define DA_OP_FINDCLOSE 18
    +#define DA_OP_CHMOD 19
    +#define DA_OP_PREAD 20
    +#define DA_OP_PWRITE 21
    +
    +#define OS_TYPE_FILE 1
    +#define OS_TYPE_DIR 2
    +#define OS_TYPE_SYMLINK 3
    +#define OS_TYPE_CHARDEV 4
    +#define OS_TYPE_BLOCKDEV 5
    +#define OS_TYPE_FIFO 6
    +#define OS_TYPE_SOCK 7
    +
    +#define DA_O_RDONLY 0
    +#define DA_O_WRONLY 1
    +#define DA_O_RDWR 2
    +#define DA_O_APPEND 8
    +#define DA_O_CREAT 0x0200
    +#define DA_O_TRUNC 0x0400
    +#define DA_O_EXCL 0x0800
    +
    +#define DA_O_AFFINITY_THREAD_0 0x10000
    +#define DA_O_AFFINITY_THREAD_1 0x20000
    +#define DA_O_AFFINITY_THREAD_2 0x40000
    +#define DA_O_AFFINITY_THREAD_3 0x80000
    +#define DA_O_AFFINITY_SHIFT 16
    +
    +#define DA_S_IWUSR 0200 /* 0x80 */
    +#define DA_S_IRUSR 0400 /* 0x100 */
    +
    +struct da_stat {
    + short st_dev;
    + unsigned short st_ino;
    + unsigned st_mode;
    + unsigned short st_nlink;
    + unsigned short st_uid;
    + unsigned short st_gid;
    + short st_rdev;
    + int st_size;
    + int st_atime;
    + int st_spare1;
    + int st_mtime;
    + int st_spare2;
    + int st_ctime;
    + int st_spare3;
    + int st_blksize;
    + int st_blocks;
    + int st_spare4[2];
    +};
    +
    +#define _A_SUBDIR 0x10
    +
    +struct da_finddata {
    + unsigned long size;
    + unsigned long attrib;
    + char name[260];
    +};
    +
    +#endif
    diff --git a/fs/imgdafs/inode.c b/fs/imgdafs/inode.c
    new file mode 100644
    index 0000000..b7d7199
    --- /dev/null
    +++ b/fs/imgdafs/inode.c
    @@ -0,0 +1,840 @@
    +/*
    + * Copyright (C) 2008,2009,2010 Imagination Technologies Ltd.
    + * Licensed under the GPL
    + *
    + * Based on hostfs for UML.
    + *
    + */
    +
    +#include <linux/fs.h>
    +#include <linux/module.h>
    +#include <linux/mm.h>
    +#include <linux/pagemap.h>
    +#include <linux/seq_file.h>
    +#include <linux/mount.h>
    +#include <linux/slab.h>
    +
    +#include <asm/da.h>
    +#include <asm/hwthread.h>
    +
    +#include "imgdafs.h"
    +
    +static int fscall(int system_call, int arg1, int arg2, int arg3, int arg4,
    + int arg5, int *fserrno)
    +{
    + register int arg1_ __asm__("D1Ar1") = arg1;
    + register int arg2_ __asm__("D0Ar2") = arg2;
    + register int arg3_ __asm__("D1Ar3") = arg3;
    + register int arg4_ __asm__("D0Ar4") = arg4;
    + register int arg5_ __asm__("D1Ar5") = arg5;
    + register int system_call_ __asm__("D0Ar6") = system_call;
    + register int result __asm__("D0Re0");
    + register int errno __asm__("D1Re0");
    +
    + __asm__ volatile (
    + "SETL [A0StP++], %7,%6\n\t"
    + "SETL [A0StP++], %5,%4\n\t"
    + "SETL [A0StP++], %3,%2\n\t"
    + "ADD A0StP, A0StP, #8\n\t"
    + "SWITCH #0x0C00208\n\t"
    + "GETL %0, %1, [A0StP+#-8]\n\t"
    + "SUB A0StP, A0StP, #(4*6)+8\n\t"
    + : "=r" (result), "=r" (errno)
    + : "r" (arg1_), "r" (arg2_), "r" (arg3_),
    + "r" (arg4_), "r" (arg5_), "r" (system_call_)
    + : "memory");
    +
    + if (fserrno)
    + *fserrno = errno;
    +
    + return result;
    +}
    +
    +struct dafs_inode_info {
    + int fd;
    + int mode;
    + struct inode vfs_inode;
    +};
    +
    +static inline struct dafs_inode_info *DAFS_I(struct inode *inode)
    +{
    + return container_of(inode, struct dafs_inode_info, vfs_inode);
    +}
    +
    +#define FILE_DAFS_I(file) DAFS_I((file)->f_path.dentry->d_inode)
    +
    +static int dafs_d_delete(const struct dentry *dentry)
    +{
    + return 1;
    +}
    +
    +static const struct dentry_operations dafs_dentry_ops = {
    + .d_delete = dafs_d_delete,
    +};
    +
    +#define DAFS_SUPER_MAGIC 0xdadadaf5
    +
    +static const struct inode_operations dafs_iops;
    +static const struct inode_operations dafs_dir_iops;
    +
    +static char *__dentry_name(struct dentry *dentry, char *name)
    +{
    + char *p = dentry_path_raw(dentry, name, PATH_MAX);
    + char *root;
    + size_t len;
    +
    + root = dentry->d_sb->s_fs_info;
    + len = strlen(root);
    + if (IS_ERR(p)) {
    + __putname(name);
    + return NULL;
    + }
    +
    + strlcpy(name, root, PATH_MAX);
    + if (len > p - name) {
    + __putname(name);
    + return NULL;
    + }
    + if (p > name + len) {
    + char *s = name + len;
    + while ((*s++ = *p++) != '\0')
    + ;
    + }
    + return name;
    +}
    +
    +static char *dentry_name(struct dentry *dentry)
    +{
    + char *name = __getname();
    + if (!name)
    + return NULL;
    +
    + return __dentry_name(dentry, name); /* will unlock */
    +}
    +
    +static int stat_file(const char *path, struct da_stat *p, int fd)
    +{
    + int ret;
    + int fserrno;
    + memset(p, 0, sizeof(*p));
    +
    + if (fd >= 0) {
    + ret = fscall(DA_OP_FSTAT, fd, (int)p, 0, 0, 0, &fserrno);
    + if (ret < 0) {
    + /* Some versions of Codescape do not fill out errno. */
    + if (ret < 0 && fserrno == 0)
    + fserrno = ENOENT;
    + return -fserrno;
    + }
    + } else {
    + ret = fscall(DA_OP_STAT, (int)path, (int)p, strlen(path), 0, 0,
    + &fserrno);
    + if (ret < 0) {
    + /* Some versions of Codescape do not fill out errno. */
    + if (ret < 0 && fserrno == 0)
    + fserrno = ENOENT;
    + return -fserrno;
    + }
    + }
    +
    + return 0;
    +}
    +
    +static struct inode *dafs_iget(struct super_block *sb)
    +{
    + struct inode *inode = new_inode(sb);
    + if (!inode)
    + return ERR_PTR(-ENOMEM);
    + return inode;
    +}
    +
    +static struct inode *dafs_alloc_inode(struct super_block *sb)
    +{
    + struct dafs_inode_info *hi;
    +
    + hi = kzalloc(sizeof(*hi), GFP_KERNEL);
    + if (hi == NULL)
    + return NULL;
    +
    + hi->fd = -1;
    + inode_init_once(&hi->vfs_inode);
    + return &hi->vfs_inode;
    +}
    +
    +static void close_file(void *stream)
    +{
    + int fd = *((int *) stream);
    +
    + fscall(DA_OP_CLOSE, fd, 0, 0, 0, 0, NULL);
    +}
    +
    +static void dafs_evict_inode(struct inode *inode)
    +{
    + truncate_inode_pages(&inode->i_data, 0);
    + clear_inode(inode);
    + if (DAFS_I(inode)->fd != -1) {
    + close_file(&DAFS_I(inode)->fd);
    + DAFS_I(inode)->fd = -1;
    + }
    +}
    +
    +static void dafs_i_callback(struct rcu_head *head)
    +{
    + struct inode *inode = container_of(head, struct inode, i_rcu);
    + kfree(DAFS_I(inode));
    +}
    +
    +static void dafs_destroy_inode(struct inode *inode)
    +{
    + call_rcu(&inode->i_rcu, dafs_i_callback);
    +}
    +
    +static const struct super_operations dafs_sbops = {
    + .alloc_inode = dafs_alloc_inode,
    + .drop_inode = generic_delete_inode,
    + .evict_inode = dafs_evict_inode,
    + .destroy_inode = dafs_destroy_inode,
    +};
    +
    +static int open_dir(char *path, struct da_finddata *finddata, int *fserrno)
    +{
    + int len = strlen(path);
    + char buf[len + 3];
    +
    + strcpy(buf, path);
    + if (buf[len - 1] != '/')
    + strcat(buf, "/*");
    + else
    + strcat(buf, "*");
    +
    + return fscall(DA_OP_FINDFIRST, (int)buf, (int)finddata, 0, 0, 0,
    + fserrno);
    +}
    +
    +static void close_dir(int handle)
    +{
    + fscall(DA_OP_FINDCLOSE, handle, 0, 0, 0, 0, NULL);
    +}
    +
    +static int read_dir(int handle, struct da_finddata *finddata)
    +{
    + return fscall(DA_OP_FINDNEXT, handle, (int)finddata, 0, 0, 0, NULL);
    +}
    +
    +static int dafs_readdir(struct file *file, void *ent, filldir_t filldir)
    +{
    + struct inode *inode = file->f_path.dentry->d_inode;
    + struct super_block *sb = inode->i_sb;
    + char *name;
    + int handle;
    + int fserrno;
    + unsigned long long next, ino;
    + int error = 0;
    + struct da_finddata finddata;
    +
    + name = dentry_name(file->f_path.dentry);
    + if (name == NULL)
    + return -ENOMEM;
    + handle = open_dir(name, &finddata, &fserrno);
    + __putname(name);
    + if (handle == -1)
    + return -fserrno;
    +
    + next = 1;
    +
    + if (file->f_pos == 0) {
    + error = (*filldir)(ent, ".", file->f_pos + 1,
    + file->f_pos, inode->i_ino,
    + DT_DIR);
    + if (error < 0)
    + goto out;
    + file->f_pos++;
    + }
    +
    + while (1) {
    + error = read_dir(handle, &finddata);
    + if (error)
    + break;
    +
    + if (next >= file->f_pos) {
    + size_t len = strlen(finddata.name);
    + ino = iunique(sb, 100);
    + error = (*filldir)(ent, finddata.name, len,
    + file->f_pos, ino,
    + (finddata.attrib & _A_SUBDIR) ?
    + DT_DIR : DT_REG);
    + if (error)
    + break;
    + file->f_pos++;
    + }
    + next++;
    + }
    +out:
    + close_dir(handle);
    + return 0;
    +}
    +
    +static int dafs_file_open(struct inode *ino, struct file *file)
    +{
    + static DEFINE_MUTEX(open_mutex);
    + char *name;
    + int mode, fmode, flags = 0, r = 0, w = 0, fd;
    + int cpu;
    +
    + fmode = file->f_mode & (FMODE_READ | FMODE_WRITE);
    + if ((fmode & DAFS_I(ino)->mode) == fmode)
    + return 0;
    +
    + mode = ino->i_mode & (DA_S_IWUSR | DA_S_IRUSR);
    +
    + mode |= DAFS_I(ino)->mode;
    +
    + DAFS_I(ino)->mode |= fmode;
    + if (DAFS_I(ino)->mode & FMODE_READ)
    + r = 1;
    + if (DAFS_I(ino)->mode & FMODE_WRITE) {
    + w = 1;
    + r = 1;
    + }
    +
    +retry:
    + if (r && !w)
    + flags |= DA_O_RDONLY;
    + else if (!r && w)
    + flags |= DA_O_WRONLY;
    + else if (r && w)
    + flags |= DA_O_RDWR;
    +
    + if (file->f_flags & O_CREAT)
    + flags |= DA_O_CREAT;
    +
    + if (file->f_flags & O_TRUNC)
    + flags |= DA_O_TRUNC;
    +
    + /*
    + * Set the affinity for this file handle to all CPUs. If we
    + * don't do this then, if the process that opened the file
    + * migrates to a different cpu, the FileServer will not accept
    + * the file handle.
    + */
    + for_each_possible_cpu(cpu) {
    + u8 hwthread = cpu_2_hwthread_id[cpu];
    + flags |= (1 << (DA_O_AFFINITY_SHIFT + hwthread));
    + }
    +
    + name = dentry_name(file->f_path.dentry);
    + if (name == NULL)
    + return -ENOMEM;
    +
    + fd = fscall(DA_OP_OPEN, (int)name, flags, mode, strlen(name), 0, NULL);
    + __putname(name);
    + if (fd < 0)
    + return fd;
    +
    + mutex_lock(&open_mutex);
    + /* somebody else had handled it first? */
    + if ((mode & DAFS_I(ino)->mode) == mode) {
    + mutex_unlock(&open_mutex);
    + return 0;
    + }
    + if ((mode | DAFS_I(ino)->mode) != mode) {
    + mode |= DAFS_I(ino)->mode;
    + mutex_unlock(&open_mutex);
    + close_file(&fd);
    + goto retry;
    + }
    + DAFS_I(ino)->fd = fd;
    + DAFS_I(ino)->mode = mode;
    + mutex_unlock(&open_mutex);
    +
    + return 0;
    +}
    +
    +static const struct file_operations dafs_file_fops = {
    + .llseek = generic_file_llseek,
    + .read = do_sync_read,
    + .splice_read = generic_file_splice_read,
    + .aio_read = generic_file_aio_read,
    + .aio_write = generic_file_aio_write,
    + .write = do_sync_write,
    + .mmap = generic_file_mmap,
    + .open = dafs_file_open,
    + .release = NULL,
    +};
    +
    +static const struct file_operations dafs_dir_fops = {
    + .llseek = generic_file_llseek,
    + .readdir = dafs_readdir,
    + .read = generic_read_dir,
    +};
    +
    +static int read_file(int fd, unsigned long long *offset, const char *buf,
    + int len)
    +{
    + int n;
    + int fserrno;
    +
    + n = fscall(DA_OP_PREAD, fd, (int)buf, len, (int)*offset, 0, &fserrno);
    +
    + if (n < 0)
    + return -fserrno;
    +
    + return n;
    +}
    +
    +static int write_file(int fd, unsigned long long *offset, const char *buf,
    + int len)
    +{
    + int n;
    + int fserrno;
    +
    + n = fscall(DA_OP_PWRITE, fd, (int)buf, len, (int)*offset, 0, &fserrno);
    +
    + if (n < 0)
    + return -fserrno;
    +
    + return n;
    +}
    +
    +static int dafs_writepage(struct page *page, struct writeback_control *wbc)
    +{
    + struct address_space *mapping = page->mapping;
    + struct inode *inode = mapping->host;
    + char *buffer;
    + unsigned long long base;
    + int count = PAGE_CACHE_SIZE;
    + int end_index = inode->i_size >> PAGE_CACHE_SHIFT;
    + int err;
    +
    + if (page->index >= end_index)
    + count = inode->i_size & (PAGE_CACHE_SIZE-1);
    +
    + buffer = kmap(page);
    + base = ((unsigned long long) page->index) << PAGE_CACHE_SHIFT;
    +
    + err = write_file(DAFS_I(inode)->fd, &base, buffer, count);
    + if (err != count) {
    + ClearPageUptodate(page);
    + goto out;
    + }
    +
    + if (base > inode->i_size)
    + inode->i_size = base;
    +
    + if (PageError(page))
    + ClearPageError(page);
    + err = 0;
    +
    + out:
    + kunmap(page);
    +
    + unlock_page(page);
    + return err;
    +}
    +
    +static int dafs_readpage(struct file *file, struct page *page)
    +{
    + char *buffer;
    + long long start;
    + int err = 0;
    +
    + start = (long long) page->index << PAGE_CACHE_SHIFT;
    + buffer = kmap(page);
    + err = read_file(FILE_DAFS_I(file)->fd, &start, buffer,
    + PAGE_CACHE_SIZE);
    + if (err < 0)
    + goto out;
    +
    + memset(&buffer[err], 0, PAGE_CACHE_SIZE - err);
    +
    + flush_dcache_page(page);
    + SetPageUptodate(page);
    + if (PageError(page))
    + ClearPageError(page);
    + err = 0;
    + out:
    + kunmap(page);
    + unlock_page(page);
    + return err;
    +}
    +
    +static int dafs_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_write_begin(mapping, index, flags);
    + if (!*pagep)
    + return -ENOMEM;
    + return 0;
    +}
    +
    +static int dafs_write_end(struct file *file, struct address_space *mapping,
    + loff_t pos, unsigned len, unsigned copied,
    + struct page *page, void *fsdata)
    +{
    + struct inode *inode = mapping->host;
    + void *buffer;
    + unsigned from = pos & (PAGE_CACHE_SIZE - 1);
    + int err;
    +
    + buffer = kmap(page);
    + err = write_file(FILE_DAFS_I(file)->fd, &pos, buffer + from, copied);
    + kunmap(page);
    +
    + if (!PageUptodate(page) && err == PAGE_CACHE_SIZE)
    + SetPageUptodate(page);
    +
    + /*
    + * If err > 0, write_file has added err to pos, so we are comparing
    + * i_size against the last byte written.
    + */
    + if (err > 0 && (pos > inode->i_size))
    + inode->i_size = pos;
    + unlock_page(page);
    + page_cache_release(page);
    +
    + return err;
    +}
    +
    +static const struct address_space_operations dafs_aops = {
    + .writepage = dafs_writepage,
    + .readpage = dafs_readpage,
    + .set_page_dirty = __set_page_dirty_nobuffers,
    + .write_begin = dafs_write_begin,
    + .write_end = dafs_write_end,
    +};
    +
    +static int read_name(struct inode *ino, char *name)
    +{
    + dev_t rdev;
    + struct da_stat st;
    + int err = stat_file(name, &st, -1);
    + if (err)
    + return err;
    +
    + /* No valid maj and min from DA.*/
    + rdev = MKDEV(0, 0);
    +
    + switch (st.st_mode & S_IFMT) {
    + case S_IFDIR:
    + ino->i_op = &dafs_dir_iops;
    + ino->i_fop = &dafs_dir_fops;
    + break;
    + case S_IFCHR:
    + case S_IFBLK:
    + case S_IFIFO:
    + case S_IFSOCK:
    + init_special_inode(ino, st.st_mode & S_IFMT, rdev);
    + ino->i_op = &dafs_iops;
    + break;
    +
    + case S_IFLNK:
    + default:
    + ino->i_op = &dafs_iops;
    + ino->i_fop = &dafs_file_fops;
    + ino->i_mapping->a_ops = &dafs_aops;
    + }
    +
    + ino->i_ino = st.st_ino;
    + ino->i_mode = st.st_mode;
    + set_nlink(ino, st.st_nlink);
    +
    + i_uid_write(ino, st.st_uid);
    + i_gid_write(ino, st.st_gid);
    + ino->i_atime.tv_sec = st.st_atime;
    + ino->i_atime.tv_nsec = 0;
    + ino->i_mtime.tv_sec = st.st_mtime;
    + ino->i_mtime.tv_nsec = 0;
    + ino->i_ctime.tv_sec = st.st_ctime;
    + ino->i_ctime.tv_nsec = 0;
    + ino->i_size = st.st_size;
    + ino->i_blocks = st.st_blocks;
    + return 0;
    +}
    +
    +static int dafs_create(struct inode *dir, struct dentry *dentry, umode_t mode,
    + bool excl)
    +{
    + struct inode *inode;
    + char *name;
    + int error, fd;
    + int damode;
    + int creat_flags = DA_O_TRUNC | DA_O_CREAT | DA_O_WRONLY;
    + int cpu;
    +
    + inode = dafs_iget(dir->i_sb);
    + if (IS_ERR(inode)) {
    + error = PTR_ERR(inode);
    + goto out;
    + }
    +
    + damode = mode & (DA_S_IWUSR | DA_S_IRUSR);
    +
    + error = -ENOMEM;
    + name = dentry_name(dentry);
    + if (name == NULL)
    + goto out_put;
    +
    + /*
    + * creat() will only create text mode files on a Windows host
    + * at present. Replicate the creat() functionality with an
    + * open() call, which always creates binary files. Set the
    + * affinity to all hardware threads.
    + */
    + for_each_possible_cpu(cpu) {
    + u8 hwthread = cpu_2_hwthread_id[cpu];
    + creat_flags |= (1 << (DA_O_AFFINITY_SHIFT + hwthread));
    + }
    +
    + fd = fscall(DA_OP_OPEN, (int)name, creat_flags, damode, strlen(name),
    + 0, NULL);
    + if (fd < 0)
    + error = fd;
    + else
    + error = read_name(inode, name);
    +
    + kfree(name);
    + if (error)
    + goto out_put;
    +
    + DAFS_I(inode)->fd = fd;
    + DAFS_I(inode)->mode = FMODE_READ | FMODE_WRITE;
    + d_instantiate(dentry, inode);
    + return 0;
    +
    + out_put:
    + iput(inode);
    + out:
    + return error;
    +}
    +
    +static struct dentry *dafs_lookup(struct inode *ino, struct dentry *dentry,
    + unsigned int flags)
    +{
    + struct inode *inode;
    + char *name;
    + int err;
    +
    + inode = dafs_iget(ino->i_sb);
    + if (IS_ERR(inode)) {
    + err = PTR_ERR(inode);
    + goto out;
    + }
    +
    + err = -ENOMEM;
    + name = dentry_name(dentry);
    + if (name == NULL)
    + goto out_put;
    +
    + err = read_name(inode, name);
    +
    + __putname(name);
    + if (err == -ENOENT) {
    + iput(inode);
    + inode = NULL;
    + } else if (err)
    + goto out_put;
    +
    + d_add(dentry, inode);
    + return NULL;
    +
    + out_put:
    + iput(inode);
    + out:
    + return ERR_PTR(err);
    +}
    +
    +static int dafs_link(struct dentry *to, struct inode *ino, struct dentry *from)
    +{
    + char *from_name, *to_name;
    + int err;
    +
    + from_name = dentry_name(from);
    + if (from_name == NULL)
    + return -ENOMEM;
    + to_name = dentry_name(to);
    + if (to_name == NULL) {
    + __putname(from_name);
    + return -ENOMEM;
    + }
    + err = -EINVAL;
    + __putname(from_name);
    + __putname(to_name);
    + return err;
    +}
    +
    +static int dafs_unlink(struct inode *ino, struct dentry *dentry)
    +{
    + char *file;
    + int err;
    + int fserrno;
    +
    + file = dentry_name(dentry);
    + if (file == NULL)
    + return -ENOMEM;
    +
    + err = fscall(DA_OP_UNLINK, (int)file, 0, 0, 0, 0, &fserrno);
    + __putname(file);
    + if (err)
    + return -fserrno;
    + return 0;
    +}
    +
    +static int do_mkdir(const char *file, int mode)
    +{
    + int err;
    + int fserrno;
    +
    + err = fscall(DA_OP_MKDIR, (int)file, mode, strlen(file), 0, 0,
    + &fserrno);
    + if (err)
    + return -fserrno;
    + return 0;
    +}
    +
    +static int dafs_mkdir(struct inode *ino, struct dentry *dentry, umode_t mode)
    +{
    + char *file;
    + int err;
    +
    + file = dentry_name(dentry);
    + if (file == NULL)
    + return -ENOMEM;
    + err = do_mkdir(file, mode);
    + __putname(file);
    + return err;
    +}
    +
    +static int do_rmdir(const char *file)
    +{
    + int err;
    + int fserrno;
    +
    + err = fscall(DA_OP_RMDIR, (int)file, strlen(file), 0, 0, 0, &fserrno);
    + if (err)
    + return -fserrno;
    + return 0;
    +}
    +
    +static int dafs_rmdir(struct inode *ino, struct dentry *dentry)
    +{
    + char *file;
    + int err;
    +
    + file = dentry_name(dentry);
    + if (file == NULL)
    + return -ENOMEM;
    + err = do_rmdir(file);
    + __putname(file);
    + return err;
    +}
    +
    +static int dafs_rename(struct inode *from_ino, struct dentry *from,
    + struct inode *to_ino, struct dentry *to)
    +{
    + char *from_name, *to_name;
    + int err;
    +
    + from_name = dentry_name(from);
    + if (from_name == NULL)
    + return -ENOMEM;
    + to_name = dentry_name(to);
    + if (to_name == NULL) {
    + __putname(from_name);
    + return -ENOMEM;
    + }
    + err = -EINVAL;
    + __putname(from_name);
    + __putname(to_name);
    + return err;
    +}
    +
    +static const struct inode_operations dafs_iops = {
    + .create = dafs_create,
    + .link = dafs_link,
    + .unlink = dafs_unlink,
    + .mkdir = dafs_mkdir,
    + .rmdir = dafs_rmdir,
    + .rename = dafs_rename,
    +};
    +
    +static const struct inode_operations dafs_dir_iops = {
    + .create = dafs_create,
    + .lookup = dafs_lookup,
    + .link = dafs_link,
    + .unlink = dafs_unlink,
    + .mkdir = dafs_mkdir,
    + .rmdir = dafs_rmdir,
    + .rename = dafs_rename,
    +};
    +
    +static char *host_root_path = ".";
    +
    +static int dafs_fill_sb_common(struct super_block *sb, void *d, int silent)
    +{
    + struct inode *root_inode;
    + int err;
    +
    + sb->s_blocksize = 1024;
    + sb->s_blocksize_bits = 10;
    + sb->s_magic = DAFS_SUPER_MAGIC;
    + sb->s_op = &dafs_sbops;
    + sb->s_d_op = &dafs_dentry_ops;
    + sb->s_maxbytes = MAX_LFS_FILESIZE;
    +
    + err = -ENOMEM;
    +
    + root_inode = new_inode(sb);
    + if (!root_inode)
    + goto out;
    +
    + err = read_name(root_inode, host_root_path);
    + if (err)
    + goto out_put;
    +
    + err = -ENOMEM;
    + sb->s_fs_info = host_root_path;
    + sb->s_root = d_make_root(root_inode);
    + if (sb->s_root == NULL)
    + goto out;
    +
    + return 0;
    +
    +out_put:
    + iput(root_inode);
    +out:
    + return err;
    +}
    +
    +static struct dentry *dafs_read_sb(struct file_system_type *type,
    + int flags, const char *dev_name,
    + void *data)
    +{
    + if (!metag_da_enabled())
    + return ERR_PTR(-ENODEV);
    + return mount_nodev(type, flags, data, dafs_fill_sb_common);
    +}
    +
    +static struct file_system_type dafs_type = {
    + .owner = THIS_MODULE,
    + .name = "imgdafs",
    + .mount = dafs_read_sb,
    + .kill_sb = kill_anon_super,
    + .fs_flags = 0,
    +};
    +
    +static int __init init_dafs(void)
    +{
    + return register_filesystem(&dafs_type);
    +}
    +
    +static void __exit exit_dafs(void)
    +{
    + unregister_filesystem(&dafs_type);
    +}
    +
    +module_init(init_dafs)
    +module_exit(exit_dafs)
    +MODULE_LICENSE("GPL");
    --
    1.7.7.6



    \
     
     \ /
      Last update: 2012-12-05 18:02    [W:4.265 / U:0.268 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site