Sample ramfs file server that uses the 9P in-kernel server implementation.
This code is for reference only, it is not supposed to be merged into the
kernel.

Signed-off-by: Latchesar Ionkov <[EMAIL PROTECTED]>
---
 net/9p/srv/Kconfig  |    6 +
 net/9p/srv/Makefile |    4 +
 net/9p/srv/ramfs.c  |  938 +++++++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 948 insertions(+), 0 deletions(-)
 create mode 100644 net/9p/srv/ramfs.c

diff --git a/net/9p/srv/Kconfig b/net/9p/srv/Kconfig
index 2013945..ecb46ef 100644
--- a/net/9p/srv/Kconfig
+++ b/net/9p/srv/Kconfig
@@ -7,3 +7,9 @@ config NET_9P_SRV
        depends on NET_9P
        help
          Say Y if you want the 9P server support
+
+config NET_9P_RAMFS
+       tristate "9P ramfs sample"
+       depends on NET_9P_SRV
+       help
+         Say Y if you want the 9P ramfs support
diff --git a/net/9p/srv/Makefile b/net/9p/srv/Makefile
index c669592..9db1c31 100644
--- a/net/9p/srv/Makefile
+++ b/net/9p/srv/Makefile
@@ -1,7 +1,11 @@
 obj-$(CONFIG_NET_9P_SRV) += 9psrv.o
+obj-$(CONFIG_NET_9P_RAMFS) += 9pramfs.o
 
 9psrv-objs := \
        srv.o \
        conn.o \
        fid.o \
        socksrv.o \
+
+9pramfs-objs := \
+       ramfs.o \
diff --git a/net/9p/srv/ramfs.c b/net/9p/srv/ramfs.c
new file mode 100644
index 0000000..45b9cde
--- /dev/null
+++ b/net/9p/srv/ramfs.c
@@ -0,0 +1,938 @@
+/*
+ * net/9p/srv/ramfs.c
+ *
+ * Simple RAM filesystem
+ *
+ *  Copyright (C) 200xz7 by Latchesar Ionkov <[EMAIL PROTECTED]>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License version 2
+ *  as published by the Free Software Foundation.
+ *
+ *  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:
+ *  Free Software Foundation
+ *  51 Franklin Street, Fifth Floor
+ *  Boston, MA  02111-1301  USA
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/errno.h>
+#include <linux/fs.h>
+#include <linux/poll.h>
+#include <linux/parser.h>
+#include <net/9p/9p.h>
+#include <net/9p/transport.h>
+#include <net/9p/srv.h>
+
+#define ROOTPERM       0777
+
+struct ramfs_file {
+       struct mutex            lock;           /* file lock */
+       atomic_t                refcount;
+       unsigned long           status;
+       char                    *name;
+       u32                     perm;
+       u64                     length;
+       u32                     atime;
+       u32                     mtime;
+       u32                     uid;
+       u32                     gid;
+       u32                     muid;
+       char                    *extension;
+       struct p9_qid           qid;
+       int                     excl;
+
+       struct ramfs_file       *parent;
+       struct ramfs_file       *next;          /* protected by parent lock */
+       struct ramfs_file       *prev;
+
+       struct ramfs_file       *dirents;       /* if directory */
+       struct ramfs_file       *dirlast;
+
+       struct list_head        fid_list;       /* all fids for a file */
+
+       u8                      *data;
+       u64                     datasize;
+};
+
+struct ramfs_fid {
+       struct ramfs_file       *file;
+       int                     omode;
+       u64                     diroffset;
+       struct ramfs_file       *dirent;
+       struct list_head        fid_list;       /* all fids for a file */
+};
+
+enum {
+       Removed = 1,
+};
+
+int debug;
+module_param(debug, int, 0);
+MODULE_PARM_DESC(debug, "Debug level");
+
+int port = 5641;
+module_param(port, int, 0);
+MODULE_PARM_DESC(port, "Port to listen on");
+
+static struct p9srv *srv;
+static struct ramfs_file *root;
+static u64 qidpath;
+static int blksize = 8192;
+
+static char *Enospace = "no space left";
+
+static void ramfs_attach(struct p9srv_req *req);
+static void ramfs_walk(struct p9srv_req *req);
+static void ramfs_open(struct p9srv_req *req);
+static void ramfs_create(struct p9srv_req *req);
+static void ramfs_read(struct p9srv_req *req);
+static void ramfs_write(struct p9srv_req *req);
+static void ramfs_clunk(struct p9srv_req *req);
+static void ramfs_remove(struct p9srv_req *req);
+static void ramfs_stat(struct p9srv_req *req);
+static void ramfs_wstat(struct p9srv_req *req);
+static void ramfs_fiddestroy(struct p9srv_fid *fid);
+static void ramfs_connopen(struct p9srv_conn *conn);
+static void ramfs_connclose(struct p9srv_conn *conn);
+
+static char *p9_strdup(struct p9_str *str)
+{
+       char *ret;
+
+       ret = kmalloc(str->len + 1, GFP_KERNEL);
+       memmove(ret, str->str, str->len);
+       ret[str->len] = '\0';
+
+       return ret;
+}
+
+static void file_incref(struct ramfs_file *f)
+{
+       if (!f)
+               return;
+
+       atomic_inc(&f->refcount);
+       P9_DPRINTK(P9SRV_DEBUG_FS, "file %p %s count %d\n", f, f->name,
+               atomic_read(&f->refcount));
+}
+
+static void file_decrefimpl(struct ramfs_file *f, int lock)
+{
+       int n;
+
+       if (!f)
+               return;
+
+       n = atomic_dec_and_test(&f->refcount);
+       P9_DPRINTK(P9SRV_DEBUG_FS, "file %p %s count %d\n", f, f->name,
+               atomic_read(&f->refcount));
+       if (n) {
+               P9_DPRINTK(P9SRV_DEBUG_FS, "file %p %s destroy\n", f, f->name);
+               if (lock)
+                       mutex_lock(&f->lock);
+
+               kfree(f->name);
+               kfree(f->extension);
+               kfree(f->data);
+               if (lock)
+                       mutex_unlock(&f->lock);
+               kfree(f);
+       }
+}
+
+static void file_decref0(struct ramfs_file *f)
+{
+       return file_decrefimpl(f, 0);
+}
+
+static void file_decref(struct ramfs_file *f)
+{
+       return file_decrefimpl(f, 1);
+}
+
+static int file_truncate(struct ramfs_file *f, u32 size)
+{
+       int n;
+       u8 *buf;
+
+       if (size == 0) {
+               kfree(f->data);
+               f->data = NULL;
+               f->datasize = 0;
+               return 0;
+       }
+
+       n = (size/blksize + (size%blksize?1:0)) * blksize;
+       buf = krealloc(f->data, n, GFP_KERNEL);
+       if (!buf)
+               return -1;
+
+       f->data = buf;
+       f->datasize = n;
+       return 0;
+}
+
+static struct ramfs_file *
+find_file(struct ramfs_file *dir, char *name, int lock)
+{
+       struct ramfs_file *ret;
+       struct ramfs_file *f;
+
+       if (strcmp(name, "..") == 0)
+               return dir->parent;
+
+       ret = NULL;
+       if (lock)
+               mutex_lock(&dir->lock);
+
+       for (f = dir->dirents; f != NULL; f = f->next) {
+               P9_DPRINTK(P9SRV_DEBUG_FS, "dir %p '%s' child %p '%s'\n", dir,
+                       dir->name, f, f->name);
+
+               if (strcmp(name, f->name) == 0) {
+                       ret = f;
+                       file_incref(f);
+                       break;
+               }
+       }
+
+       if (lock)
+               mutex_unlock(&dir->lock);
+
+       return ret;
+}
+
+static int check_perm(struct p9srv_req *req, struct ramfs_file *dir,
+       u32 uid, int perm)
+{
+       int n;
+
+       if (!perm)
+               return 1;
+
+       n = dir->perm & 7;
+       if (dir->uid == uid) {
+               n |= (dir->perm >> 6) & 7;
+               n |= (dir->perm >> 3) & 7;
+       }
+
+       if (!(n & perm)) {
+               p9srv_respond_error(req, Eperm, EPERM);
+               return 0;
+       }
+
+       return 1;
+}
+
+/* called holding parent lock, if parent != NULL */
+static struct ramfs_file *file_create(struct ramfs_file *parent, char *name,
+       int perm, u32 uid, u32 gid)
+{
+       struct ramfs_file *file;
+
+       file = kmalloc(sizeof(*file), GFP_KERNEL);
+       mutex_init(&file->lock);
+       atomic_set(&file->refcount, 1);
+       file->status = 0;
+       file->name = name;
+       file->perm = perm;
+       file->length = 0;
+       file->atime = 0;
+       file->mtime = 0;
+       file->uid = uid;
+       file->gid = gid;
+       file->muid = uid;
+       file->extension = NULL;
+       file->excl = 0;
+
+       file->parent = parent;
+       file->next = NULL;
+       file->prev = NULL;
+       file->dirents = NULL;
+       file->dirlast = NULL;
+       file->data = NULL;
+       file->datasize = 0;
+       file_truncate(file, 0);
+       file->qid.type = perm >> 24;
+       file->qid.version = 0;
+       file->qid.path = qidpath++;
+       INIT_LIST_HEAD(&file->fid_list);
+
+       if (parent) {
+               if (parent->dirlast) {
+                       parent->dirlast->next = file;
+                       file->prev = parent->dirlast;
+               } else
+                       parent->dirents = file;
+
+               parent->dirlast = file;
+               parent->muid = uid;
+/*             parent->mtime = time(NULL); */
+               parent->qid.version++;
+               file_incref(parent);
+       }
+
+       P9_DPRINTK(P9SRV_DEBUG_FS, "file %p %s\n", file, file->name);
+       return file;
+}
+
+static void file2wstat(struct ramfs_file *f, struct p9_wstat *wstat)
+{
+       wstat->size = 0;
+       wstat->type = 0;
+       wstat->dev = 0;
+       wstat->qid = f->qid;
+       wstat->mode = f->perm;
+       wstat->atime = f->atime;
+       wstat->mtime = f->mtime;
+       wstat->length = f->length;
+       wstat->name = f->name;
+       wstat->uid = NULL;
+       wstat->gid = NULL;
+       wstat->muid = NULL;
+       wstat->extension = f->extension;
+       wstat->n_uid = f->uid;
+       wstat->n_gid = f->gid;
+       wstat->n_muid = f->muid;
+}
+
+static struct ramfs_fid *fid_alloc(struct ramfs_file *file)
+{
+       struct ramfs_fid *f;
+
+       f = kmalloc(sizeof(*f), GFP_KERNEL);
+       f->file = file;
+       file_incref(file);
+       f->omode = -1;
+       f->diroffset = 0;
+       f->dirent = NULL;
+       INIT_LIST_HEAD(&f->fid_list);
+
+       mutex_lock(&file->lock);
+       list_add_tail(&f->fid_list, &file->fid_list);
+       mutex_unlock(&file->lock);
+
+       P9_DPRINTK(P9SRV_DEBUG_FS, "fid %p file %s\n", f, file->name);
+       return f;
+}
+
+/* file is already incref-ed */
+static void fid_move(struct ramfs_fid *fid, struct ramfs_file *file)
+{
+       P9_DPRINTK(P9SRV_DEBUG_FS, "fid %p from %s to %s\n", fid,
+               fid->file->name, file->name);
+
+       mutex_lock(&fid->file->lock);
+       list_del(&fid->fid_list);
+       mutex_unlock(&fid->file->lock);
+       file_decref(fid->file);
+
+       fid->file = file;
+       mutex_lock(&fid->file->lock);
+       list_add(&fid->fid_list, &fid->file->fid_list);
+       mutex_unlock(&fid->file->lock);
+}
+
+static void ramfs_fiddestroy(struct p9srv_fid *fid)
+{
+       struct ramfs_fid *f;
+
+       f = fid->aux;
+       if (!f)
+               return;
+
+       mutex_lock(&f->file->lock);
+       list_del(&f->fid_list);
+       mutex_unlock(&f->file->lock);
+
+       file_decref(f->file);
+       file_decref(f->dirent);
+       kfree(f);
+}
+
+static void ramfs_attach(struct p9srv_req *req)
+{
+       struct ramfs_fid *fid;
+       struct p9_fcall *rc;
+
+       if (req->afid != NULL) {
+               p9srv_respond_error(req, Enoauth, EIO);
+               return;
+       }
+
+       if (!check_perm(req, root, req->tcall->params.tattach.n_uname, 4))
+               return;
+
+       req->fid->uid = req->tcall->params.tattach.n_uname;
+       fid = fid_alloc(root);
+       req->fid->aux = fid;
+
+       rc = p9_create_rattach(&fid->file->qid);
+       p9srv_respond(req, rc);
+}
+
+static void ramfs_walk(struct p9srv_req *req)
+{
+       int i;
+       char *name;
+       struct ramfs_fid *fid, *nfid;
+       struct ramfs_file *nf;
+       struct p9_fcall *tc, *rc;
+       struct p9_qid wqids[P9_MAXWELEM];
+
+       P9_DPRINTK(P9SRV_DEBUG_FS, "fid %d nfid %d nwname %d\n", req->fid->fid,
+               req->newfid->fid, req->tcall->params.twalk.nwname);
+
+       if (req->fid != req->newfid) {
+               fid = req->fid->aux;
+               nfid = fid_alloc(fid->file);
+               req->newfid->aux = nfid;
+       }
+
+       tc = req->tcall;
+       if (tc->params.twalk.nwname == 0) {
+               i = 0;
+               goto done;
+       }
+
+       nfid = req->newfid->aux;
+       for (i = 0; i < tc->params.twalk.nwname; i++) {
+               name = p9_strdup(&tc->params.twalk.wnames[i]);
+               nf = find_file(nfid->file, name, 1);
+               kfree(name);
+               if (!nf)
+                       break;
+
+               wqids[i] = nf->qid;
+               fid_move(nfid, nf);
+       }
+
+       if (i == 0) {
+               p9srv_respond_error(req, Enotfound, ENOENT);
+               return;
+       }
+
+done:
+       rc = p9_create_rwalk(i, wqids);
+       p9srv_respond(req, rc);
+}
+
+static void ramfs_open(struct p9srv_req *req)
+{
+       int m, mode;
+       struct ramfs_fid *fid;
+       struct ramfs_file *file;
+       struct p9_fcall *rc;
+
+       rc = NULL;
+       fid = req->fid->aux;
+       mode = req->tcall->params.topen.mode;
+       m = 0;
+       switch (mode & 3) {
+       case P9_OREAD:
+               m = 4;
+               break;
+
+       case P9_OWRITE:
+               m = 2;
+               break;
+
+       case P9_ORDWR:
+               m = 6;
+               break;
+
+       case P9_OEXEC:
+               m = 1;
+               break;
+       }
+
+       if (mode & P9_OTRUNC)
+               m |= 2;
+
+       file = fid->file;
+       mutex_lock(&file->lock);
+       if (!check_perm(req, file, req->fid->uid, m))
+               goto done;
+
+       if (mode & P9_OTRUNC)
+               file_truncate(file, 0);
+
+       if (mode & P9_OEXCL) {
+               if (file->excl) {
+                       p9srv_respond_error(req, Eopen, EPERM);
+                       goto done;
+               }
+
+               file->excl = 1;
+       }
+
+       fid->omode = mode;
+       rc = p9_create_ropen(&file->qid, 0);
+
+done:
+       mutex_unlock(&file->lock);
+       if (rc)
+               p9srv_respond(req, rc);
+}
+
+static void ramfs_create(struct p9srv_req *req)
+{
+       int m, mode;
+       u32 perm;
+       struct p9_fcall *tc, *rc;
+       struct ramfs_fid *fid;
+       struct ramfs_file *dir, *file, *nf;
+       char *sname;
+
+       rc = NULL;
+       tc = req->tcall;
+       perm = tc->params.tcreate.perm;
+       mode = tc->params.tcreate.mode;
+       sname = NULL;
+       file = NULL;
+
+       if (perm & P9_DMLINK) {
+               p9srv_respond_error(req, Eperm, EPERM);
+               goto done;
+       }
+
+       fid = req->fid->aux;
+       dir = fid->file;
+       sname = p9_strdup(&tc->params.tcreate.name);
+       if (!strcmp(sname, ".") || !strcmp(sname, "..")) {
+               p9srv_respond_error(req, Eexist, EEXIST);
+               goto done;
+       }
+
+       if (!check_perm(req, dir, req->fid->uid, 2))
+               goto done;
+
+       if (perm & P9_DMDIR)
+               perm &= ~0777 | (dir->perm & 0777);
+       else
+               perm &= ~0666 | (dir->perm & 0666);
+
+       mutex_lock(&dir->lock);
+       nf = find_file(dir, sname, 0);
+       if (nf) {
+               mutex_unlock(&dir->lock);
+               file_decref(nf);
+               p9srv_respond_error(req, Eexist, EEXIST);
+               goto done;
+       }
+
+       file = file_create(dir, sname, perm, dir->uid, 0);
+       mutex_unlock(&dir->lock);
+
+       fid->omode = mode;
+       file_incref(file);
+       fid_move(fid, file);
+       if (perm & (P9_DMNAMEDPIPE | P9_DMSYMLINK | P9_DMLINK | P9_DMDEVICE |
+               P9_DMSOCKET)) {
+
+               file->extension = p9_strdup(&tc->params.tcreate.extension);
+       } else {
+               if (mode & P9_OEXCL)
+                       file->excl = 1;
+       }
+
+       P9_DPRINTK(P9SRV_DEBUG_FS, "file %p parent %p first child %p\n",
+               file, dir, dir->dirents);
+       rc = p9_create_rcreate(&file->qid, 0);
+
+done:
+       if (!rc)
+               kfree(sname);
+       if (rc)
+               p9srv_respond(req, rc);
+}
+
+static void ramfs_read(struct p9srv_req *req)
+{
+       int i, n, count;
+       u64 offset;
+       struct p9_fcall *tc, *rc;
+       struct ramfs_fid *fid;
+       struct ramfs_file *file, *cf;
+       u8 *buf;
+       struct p9_wstat wstat;
+
+       tc = req->tcall;
+       rc = NULL;
+       fid = req->fid->aux;
+       count = tc->params.tread.count;
+       offset = tc->params.tread.offset;
+       rc = p9_alloc_rread(count);
+       buf = rc->params.rread.data;
+       file = fid->file;
+       if (file->perm & P9_DMDIR) {
+               mutex_lock(&file->lock);
+               if (offset == 0) {
+                       file_decref(fid->dirent);
+                       fid->dirent = file->dirents;
+                       file_incref(fid->dirent);
+                       fid->diroffset = 0;
+               }
+
+               n = 0;
+               cf = fid->dirent;
+               for (n = 0, cf = fid->dirent; (n < count) && (cf != NULL);
+                                                       cf = cf->next) {
+                       BUG_ON(test_bit(Removed, &cf->status));
+                       file2wstat(cf, &wstat);
+                       i = p9_serialize_stat(&wstat, buf + n, count - n - 1,
+                               req->conn->dotu);
+
+                       if (i == 0)
+                               break;
+
+                       n += i;
+               }
+
+               fid->diroffset += n;
+               file_incref(cf);
+               file_decref(fid->dirent);
+               fid->dirent = cf;
+               mutex_unlock(&file->lock);
+       } else {
+               n = count;
+               if (file->length < offset+count)
+                       n = file->length - offset;
+
+               if (n < 0)
+                       n = 0;
+
+               memmove(buf, file->data + offset, n);
+       }
+
+/*
+       pthread_mutex_lock(&file->lock);
+       file->atime = time(NULL);
+       pthread_mutex_unlock(&file->lock);
+*/
+
+       p9_set_rread_count(rc, n);
+       p9srv_respond(req, rc);
+}
+
+static void ramfs_write(struct p9srv_req *req)
+{
+       u32 count;
+       u64 offset;
+       struct p9_fcall *tc, *rc;
+       struct ramfs_fid *fid;
+       struct ramfs_file *file;
+
+       tc = req->tcall;
+       offset = tc->params.twrite.offset;
+       count = tc->params.twrite.count;
+       fid = req->fid->aux;
+       file = fid->file;
+       if (req->fid->omode & P9_OAPPEND)
+               offset = file->length;
+
+       if (file->length < offset+count) {
+               mutex_lock(&file->lock);
+               if (file_truncate(file, offset+count)) {
+                       mutex_unlock(&file->lock);
+                       p9srv_respond_error(req, Enospace, ENOSPC);
+                       return;
+               }
+
+               if (offset+count > file->datasize) {
+                       if (file->datasize - offset > 0)
+                               count = file->datasize - offset;
+                       else
+                               count = 0;
+               }
+
+               if (count) {
+                       if (file->length < offset)
+                               memset(file->data+file->length, 0,
+                                       offset - file->length);
+
+                       file->length = offset+count;
+               }
+               mutex_unlock(&file->lock);
+       }
+
+       if (count)
+               memmove(file->data + offset, tc->params.twrite.data, count);
+
+       mutex_lock(&file->lock);
+       file->qid.version++;
+       file->muid = req->fid->uid;
+       mutex_unlock(&file->lock);
+
+       rc = p9_create_rwrite(count);
+       p9srv_respond(req, rc);
+}
+
+static void ramfs_clunk(struct p9srv_req *req)
+{
+       p9srv_respond(req, p9_create_rclunk());
+}
+
+static void ramfs_remove(struct p9srv_req *req)
+{
+       struct p9_fcall *rc;
+       struct ramfs_fid *fid, *f;
+       struct ramfs_file *file;
+
+       rc = NULL;
+       fid = req->fid->aux;
+       file = fid->file;
+       P9_DPRINTK(P9SRV_DEBUG_FS, "fid %d name %s\n", req->fid->fid,
+               file->name);
+       mutex_lock(&file->lock);
+       if (file->perm & P9_DMDIR && file->dirents) {
+               mutex_unlock(&file->lock);
+               p9srv_respond_error(req, Enotempty, ENOTEMPTY);
+               return;
+       }
+       mutex_unlock(&file->lock);
+
+       mutex_lock(&file->parent->lock);
+       if (!check_perm(req, file->parent, req->fid->uid, 2))
+               goto done;
+
+       if (test_and_set_bit(Removed, &file->status))
+               goto respond;
+
+       if (file->parent->dirents == file)
+               file->parent->dirents = file->next;
+       else
+               file->prev->next = file->next;
+
+       if (file->next)
+               file->next->prev = file->prev;
+
+       if (file == file->parent->dirlast)
+               file->parent->dirlast = file->prev;
+
+       /* check if any fid has dirent set to the removed file */
+       list_for_each_entry(f, &file->parent->fid_list, fid_list) {
+               if (f->dirent == file) {
+                       file_incref(file->next);
+                       f->dirent = file->next;
+                       file_decref(f->dirent);
+               }
+       }
+
+       file->prev = NULL;
+       file->next = NULL;
+
+       file->parent->muid = req->fid->uid;
+       file->parent->qid.version++;
+
+       file_decref(file);
+       file_decref0(file->parent);
+
+respond:
+       rc = p9_create_rremove();
+
+done:
+       mutex_unlock(&file->parent->lock);
+       if (rc)
+               p9srv_respond(req, rc);
+}
+
+static void ramfs_stat(struct p9srv_req *req)
+{
+       struct ramfs_fid *f;
+       struct p9_wstat wstat;
+
+       f = req->fid->aux;
+       file2wstat(f->file, &wstat);
+       p9srv_respond(req, p9_create_rstat(&wstat, req->conn->dotu));
+}
+
+static void ramfs_wstat(struct p9srv_req *req)
+{
+       int lockparent, lockfile;
+       struct ramfs_fid *f;
+       struct ramfs_file *file, *nf;
+       struct p9_fcall *rc;
+       struct p9_stat *stat;
+       char *sname, *oldname;
+       u64 length, oldlength;
+       u32 oldperm;
+       u32 oldmtime;
+
+       rc = NULL;
+       oldlength = ~0;
+       oldperm = ~0;
+       oldmtime = ~0;
+       oldname = NULL;
+
+       f = req->fid->aux;
+       file = f->file;
+       stat = &req->tcall->params.twstat.stat;
+
+       mutex_lock(&file->lock);
+       lockfile = 1;
+
+       lockparent = stat->name.len != 0 && file->parent != file;
+       if (lockparent)
+               mutex_lock(&file->parent->lock);
+
+       oldname = NULL;
+       if (stat->name.len != 0) {
+               if (!check_perm(req, file->parent, req->fid->uid, 2))
+                       goto out;
+
+               sname = p9_strdup(&stat->name);
+               nf = find_file(file->parent, sname, 0);
+
+               if (nf) {
+                       kfree(sname);
+                       p9srv_respond_error(req, Eexist, EEXIST);
+                       goto out;
+               }
+
+               oldname = file->name;
+               file->name = sname;
+       }
+
+       if (stat->length != (u64) ~0) {
+               if (!check_perm(req, file, req->fid->uid, 2) ||
+                                                       file->perm & P9_DMDIR)
+                       goto out;
+
+               oldlength = file->length;
+               length = stat->length;
+               if (file_truncate(file, length)) {
+                       p9srv_respond_error(req, Enospace, ENOSPC);
+                       goto out;
+               }
+
+               if (length > file->datasize)
+                       length = file->datasize;
+
+               if (file->length < length)
+                       memset(file->data+file->length, 0, length-file->length);
+
+               file->length = length;
+       }
+
+       if (stat->mode != (u32) ~0) {
+               if (file->uid != req->fid->uid) {
+                       p9srv_respond_error(req, Eperm, EPERM);
+                       goto out;
+               }
+
+               oldperm = file->perm;
+               file->perm = stat->mode;
+       }
+
+       if (stat->mtime != (u32) ~0) {
+               if (file->uid != req->fid->uid) {
+                       p9srv_respond_error(req, Eperm, EPERM);
+                       goto out;
+               }
+
+               oldmtime = file->mtime;
+               file->mtime = stat->mtime;
+       }
+
+       rc = p9_create_rwstat();
+
+out:
+       if (!rc) {
+               if (oldname) {
+                       kfree(file->name);
+                       file->name = oldname;
+               }
+
+               if (oldperm != ~0)
+                       file->perm = oldperm;
+
+               if (oldmtime != ~0)
+                       file->mtime = oldmtime;
+
+               if (oldlength != ~0) {
+                       file->length = oldlength;
+                       file_truncate(file, oldlength);
+               }
+       } else {
+               kfree(oldname);
+               if (stat->length != ~0) {
+                       file_truncate(file, file->length);
+                       memset(file->data + file->length, 0,
+                               file->datasize - file->length);
+               }
+       }
+
+       if (lockparent)
+               mutex_unlock(&file->parent->lock);
+
+       if (lockfile)
+               mutex_unlock(&file->lock);
+
+       if (rc)
+               p9srv_respond(req, rc);
+}
+
+static void ramfs_connopen(struct p9srv_conn *conn)
+{
+       try_module_get(THIS_MODULE);
+}
+
+static void ramfs_connclose(struct p9srv_conn *conn)
+{
+       module_put(THIS_MODULE);
+}
+
+static int __init p9srv_init(void)
+{
+       char *s;
+
+       srv = p9srv_socksrv_create(port);
+       if (IS_ERR(srv))
+               return PTR_ERR(srv);
+
+       srv->attach = ramfs_attach;
+       srv->walk = ramfs_walk;
+       srv->open = ramfs_open;
+       srv->create = ramfs_create;
+       srv->read = ramfs_read;
+       srv->write = ramfs_write;
+       srv->clunk = ramfs_clunk;
+       srv->remove = ramfs_remove;
+       srv->stat = ramfs_stat;
+       srv->wstat = ramfs_wstat;
+       srv->fiddestroy = ramfs_fiddestroy;
+       srv->debuglevel = debug;
+       srv->connopen = ramfs_connopen;
+       srv->connclose = ramfs_connclose;
+
+       s = kmalloc(2, GFP_KERNEL);
+       *s = '\0';
+       root = file_create(NULL, s, ROOTPERM | P9_DMDIR, 0, 0);
+       file_incref(root);
+       root->parent = root;
+
+       p9srv_srv_start(srv);
+
+       return 0;
+}
+
+static void __exit p9srv_exit(void)
+{
+       p9srv_srv_stop(srv);
+}
+
+module_init(p9srv_init)
+module_exit(p9srv_exit)
+
+MODULE_AUTHOR("Latchesar Ionkov <[EMAIL PROTECTED]>");
+MODULE_LICENSE("GPL");
-- 
1.5.2.4

-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to [EMAIL PROTECTED]
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

Reply via email to