[PATCH][REFERENCE ONLY] 9p: ramfs 9p server

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Sample ramfs file server that uses the in-kernel 9P file server support.
This code is for reference only.

Signed-off-by: Latchesar Ionkov <[email protected]>

---
 net/9p/Kconfig       |    8 +-
 net/9p/Makefile      |    1 +
 net/9p/ramfs/ramfs.c |  986 ++++++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 994 insertions(+), 1 deletions(-)

diff --git a/net/9p/Kconfig b/net/9p/Kconfig
index 5b0dc28..68f7496 100644
--- a/net/9p/Kconfig
+++ b/net/9p/Kconfig
@@ -23,11 +23,17 @@ config NET_9P_FD
 	  file descriptors.  TCP/IP is the default transport for 9p,
 	  so if you are going to use 9p, you'll likely want this.
 
-config NET_9P_SRV
+menuconfig NET_9P_SRV
 	tristate "9P server support"
 	depends on NET_9P
 	help
 	  Say Y if you want the 9P server support
+
+config NET_9P_RAMFS
+        tristate "9P ramfs sample file server"
+        depends on NET_9P_SRV && NET_9P_LOOP
+        help
+          Say Y if you want the 9P ramfs support
 config NET_9P_VIRTIO
 	depends on NET_9P && EXPERIMENTAL && VIRTIO
 	tristate "9P Virtio Transport (Experimental)"
diff --git a/net/9p/Makefile b/net/9p/Makefile
index 6ee024e..3808c40 100644
--- a/net/9p/Makefile
+++ b/net/9p/Makefile
@@ -3,6 +3,7 @@ obj-$(CONFIG_NET_9P_FD) += 9pnet_fd.o
 obj-$(CONFIG_NET_9P_LOOP) += 9pnet_loop.o
 obj-$(CONFIG_NET_9P_SRV) += 9psrv.o
 obj-$(CONFIG_NET_9P_VIRTIO) += 9pnet_virtio.o
+obj-$(CONFIG_NET_9P_RAMFS) += ramfs/
 
 9pnet-objs := \
 	mod.o \
diff --git a/net/9p/ramfs/ramfs.c b/net/9p/ramfs/ramfs.c
new file mode 100644
index 0000000..3aff620
--- /dev/null
+++ b/net/9p/ramfs/ramfs.c
@@ -0,0 +1,986 @@
+/*
+ * net/9p/srv/ramfs.c
+ *
+ * Simple RAM filesystem
+ *
+ *  Copyright (C) 2007 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,
+};
+
+static struct p9srv_type *ramfs_srv_type;
+static struct ramfs_file *root;
+static u64 qidpath;
+static int blksize = 8192;
+
+static char *Enospace = "no space left";
+static char *Einternal = "internal error";
+
+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;
+	if (n <= f->datasize)
+		return 0;
+
+	buf = kmalloc(n, GFP_KERNEL);
+	if (!buf)
+		return -1;
+
+	memmove(buf, f->data, f->length);
+	kfree(f->data);
+	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)
+{
+	int err;
+	struct ramfs_fid *fid;
+
+	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;
+
+	err = p9_create_rattach(req->rcall, &fid->file->qid);
+	if (err < 0)
+		p9srv_respond_error(req, Einternal, err);
+	else
+		p9srv_respond(req, req->rcall);
+}
+
+static void ramfs_walk(struct p9srv_req *req)
+{
+	int i, err;
+	char *name;
+	struct ramfs_fid *fid, *nfid;
+	struct ramfs_file *nf;
+	struct p9_fcall *tc;
+	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:
+	err = p9_create_rwalk(req->rcall, i, wqids);
+	if (err < 0)
+		p9srv_respond_error(req, Einternal, err);
+	else
+		p9srv_respond(req, req->rcall);
+}
+
+static void ramfs_open(struct p9srv_req *req)
+{
+	int m, mode, err;
+	struct ramfs_fid *fid;
+	struct ramfs_file *file;
+
+	err = 0;
+	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;
+	err = p9_create_ropen(req->rcall, &file->qid, 0);
+	if (err < 0)
+		p9srv_respond_error(req, Einternal, err);
+
+done:
+	mutex_unlock(&file->lock);
+	if (err >= 0)
+		p9srv_respond(req, req->rcall);
+}
+
+static void ramfs_create(struct p9srv_req *req)
+{
+	int mode, err;
+	u32 perm;
+	struct p9_fcall *tc;
+	struct ramfs_fid *fid;
+	struct ramfs_file *dir, *file, *nf;
+	char *sname;
+
+	err = 0;
+	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);
+	P9_DPRINTK(P9SRV_DEBUG_FS, "name %s\n", sname);
+	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);
+	err = p9_create_rcreate(req->rcall, &file->qid, 0);
+	if (err < 0)
+		p9srv_respond_error(req, Einternal, err);
+
+done:
+	if (!sname)
+		kfree(sname);
+
+	if (err >= 0)
+		p9srv_respond(req, req->rcall);
+}
+
+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;
+	struct p9_wstat wstat;
+	u8 *data;
+
+	tc = req->tcall;
+	rc = req->rcall;
+	n = p9_init_rread(rc);
+	fid = req->fid->aux;
+	count = tc->params.tread.count;
+	offset = tc->params.tread.offset;
+	data = 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;
+		}
+
+		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);
+			P9_DPRINTK(P9SRV_DEBUG_FS, "name %s\n", wstat.name);
+			i = p9_serialize_stat(&wstat, data + 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(data, 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)
+{
+	int err;
+	u32 count;
+	u64 offset;
+	struct p9_fcall *tc;
+	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);
+
+	err = p9_create_rwrite(req->rcall, count);
+	if (err < 0)
+		p9srv_respond_error(req, Einternal, err);
+	else
+		p9srv_respond(req, req->rcall);
+}
+
+static void ramfs_clunk(struct p9srv_req *req)
+{
+	int err;
+
+	err = p9_create_rclunk(req->rcall);
+	if (err < 0)
+		p9srv_respond_error(req, Einternal, err);
+	else
+		p9srv_respond(req, req->rcall);
+}
+
+static void ramfs_remove(struct p9srv_req *req)
+{
+	int err;
+	struct p9_fcall *rc;
+	struct ramfs_fid *fid, *f;
+	struct ramfs_file *file;
+
+	err = 0;
+	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:
+	err = p9_create_rremove(req->rcall);
+
+done:
+	mutex_unlock(&file->parent->lock);
+	if (err < 0)
+		p9srv_respond_error(req, Einternal, err);
+	else
+		p9srv_respond(req, req->rcall);
+}
+
+static void ramfs_stat(struct p9srv_req *req)
+{
+	int err;
+	struct ramfs_fid *f;
+	struct p9_wstat wstat;
+
+	f = req->fid->aux;
+	file2wstat(f->file, &wstat);
+	err = p9_create_rstat(req->rcall, &wstat, req->conn->dotu);
+	if (err < 0)
+		p9srv_respond_error(req, Einternal, err);
+	else
+		p9srv_respond(req, req->rcall);
+}
+
+static void ramfs_wstat(struct p9srv_req *req)
+{
+	int lockparent, lockfile, err;
+	struct ramfs_fid *f;
+	struct ramfs_file *file, *nf;
+	struct p9_stat *stat;
+	struct p9_fcall *rc;
+	char *sname, *oldname;
+	u64 length, oldlength;
+	u32 oldperm;
+	u32 oldmtime;
+
+	rc = NULL;
+	err = 0;
+	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;
+	}
+
+	err = p9_create_rwstat(req->rcall);
+	if (err < 0)
+		p9srv_respond_error(req, Einternal, err);
+	else
+		rc = req->rcall;
+
+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 void ramfs_destroy(struct p9srv *srv)
+{
+	module_put(THIS_MODULE);
+}
+
+static struct p9srv *ramfs_srv_create(void)
+{
+	char *s;
+	struct p9srv *srv;
+
+	srv = p9srv_srv_create();
+	if (IS_ERR(srv))
+		return 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->destroy = ramfs_destroy;
+	srv->fiddestroy = ramfs_fiddestroy;
+	srv->debuglevel = 0;
+	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;
+
+	try_module_get(THIS_MODULE);
+	p9srv_srv_start(srv);
+	return srv;
+}
+
+static int __init ramfs_init(void)
+{
+	ramfs_srv_type = p9srv_type_register("ramfs", ramfs_srv_create);
+	if (IS_ERR(ramfs_srv_type))
+		return PTR_ERR(ramfs_srv_type);
+
+	return 0;
+}
+
+static void __exit ramfs_exit(void)
+{
+	p9srv_type_unregister("ramfs");
+}
+
+module_init(ramfs_init)
+module_exit(ramfs_exit)
+
+MODULE_AUTHOR("Latchesar Ionkov <[email protected]>");
+MODULE_LICENSE("GPL");
-
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/

[Index of Archives]     [Kernel Newbies]     [Netfilter]     [Bugtraq]     [Photo]     [Stuff]     [Gimp]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Video 4 Linux]     [Linux for the blind]     [Linux Resources]
  Powered by Linux