From e63ae1e7a8360946f96635072e7a15dfff9923ec Mon Sep 17 00:00:00 2001 From: jankratochvil <> Date: Thu, 13 Nov 2003 20:17:24 +0000 Subject: [PATCH] This commit was manufactured by cvs2svn to create branch 'captive'. Cherrypick from master 2003-11-13 20:17:21 UTC short 'http://prdownloads.sourceforge.net/lufs/lufs-0.9.7.tar.gz?download': kernel/Linux/2.6/Makefile kernel/Linux/2.6/dir.c kernel/Linux/2.6/file.c kernel/Linux/2.6/inode.c kernel/Linux/2.6/lufs.h kernel/Linux/2.6/proc.c kernel/Linux/2.6/proc.h kernel/Linux/2.6/symlink.c --- kernel/Linux/2.6/Makefile | 12 + kernel/Linux/2.6/dir.c | 582 +++++++++++++++++++++++++++++++++++++++++++++ kernel/Linux/2.6/file.c | 321 +++++++++++++++++++++++++ kernel/Linux/2.6/inode.c | 535 +++++++++++++++++++++++++++++++++++++++++ kernel/Linux/2.6/lufs.h | 87 +++++++ kernel/Linux/2.6/proc.c | 505 +++++++++++++++++++++++++++++++++++++++ kernel/Linux/2.6/proc.h | 51 ++++ kernel/Linux/2.6/symlink.c | 184 ++++++++++++++ 8 files changed, 2277 insertions(+) create mode 100644 kernel/Linux/2.6/Makefile create mode 100644 kernel/Linux/2.6/dir.c create mode 100644 kernel/Linux/2.6/file.c create mode 100644 kernel/Linux/2.6/inode.c create mode 100644 kernel/Linux/2.6/lufs.h create mode 100644 kernel/Linux/2.6/proc.c create mode 100644 kernel/Linux/2.6/proc.h create mode 100644 kernel/Linux/2.6/symlink.c diff --git a/kernel/Linux/2.6/Makefile b/kernel/Linux/2.6/Makefile new file mode 100644 index 0000000..7dfc663 --- /dev/null +++ b/kernel/Linux/2.6/Makefile @@ -0,0 +1,12 @@ +ifneq ($(KERNELRELEASE),) +obj-m := lufs.o +lufs-objs := proc.o inode.o dir.o file.o symlink.o + +else +KDIR=/lib/modules/`uname -r`/build +PWD=`pwd` + +.DEFAULT: + $(MAKE) -C $(KDIR) SUBDIRS=$(PWD) modules + +endif diff --git a/kernel/Linux/2.6/dir.c b/kernel/Linux/2.6/dir.c new file mode 100644 index 0000000..0835ad8 --- /dev/null +++ b/kernel/Linux/2.6/dir.c @@ -0,0 +1,582 @@ +/* + * dir.c + * Copyright (C) 2002 Florin Malita + * + * This file is part of LUFS, a free userspace filesystem implementation. + * See http://lufs.sourceforge.net/ for updates. + * + * LUFS 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. + * + * LUFS 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 + */ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include + +#include "lufs.h" +#include "proc.h" + + +extern struct inode* lu_iget(struct super_block*, struct lufs_fattr*); +extern int lufs_notify_change(struct dentry*, struct iattr*); + +static int lu_readdir(struct file*, void*, filldir_t); + +static struct dentry *lu_lookup(struct inode*, struct dentry*); +static int lu_mkdir(struct inode*, struct dentry*, int); +static int lu_create(struct inode*, struct dentry*, int); +static int lu_rmdir(struct inode*, struct dentry*); +static int lu_rename(struct inode*, struct dentry*, struct inode*, struct dentry*); +static int lu_unlink(struct inode*, struct dentry*); +static int lu_link(struct dentry*, struct inode*, struct dentry*); +static int lu_symlink(struct inode*, struct dentry*, const char*); + +struct file_operations lu_dir_operations = { + .read = generic_read_dir, + .readdir = lu_readdir, +}; + +struct inode_operations lu_dir_inode_operations = { + .create = lu_create, + .lookup = lu_lookup, + .link = lu_link, + .unlink = lu_unlink, + .symlink = lu_symlink, + .mkdir = lu_mkdir, + .rmdir = lu_rmdir, + .rename = lu_rename, + .setattr = lufs_notify_change, +}; + +static int lu_lookup_validate(struct dentry *dentry, int flags) +{ + struct inode *inode = dentry->d_inode; + unsigned long age = jiffies - dentry->d_time; + int res; + + TRACE("in\n"); + + res = (age <= LU_MAXAGE); + TRACE("age: %lu, valid: %d\n", age, res); + + if(!res) + res = (lu_revalidate_inode(dentry) == 0); + + + if(inode){ + lock_kernel(); + + if(is_bad_inode(inode)) + res = 0; + unlock_kernel(); + }else + TRACE("no inode?!\n"); + + TRACE("out(res=%d)\n", res); + + return res; +} + +static int lu_delete_dentry(struct dentry *dentry) +{ + + TRACE("in\n"); + if(dentry->d_inode && is_bad_inode(dentry->d_inode)){ + WARN("bad inode, unhashing \n"); + return 1; + } + + TRACE("out\n"); + return 0; +} + +struct dentry_operations lufs_dentry_operations = { + .d_revalidate = lu_lookup_validate, + .d_delete = lu_delete_dentry, +}; + +static int lu_readdir(struct file *f, void *dirent, filldir_t filldir) +{ + int res = -1; + char *c; + struct qstr qname; + unsigned long ino; + struct iovec siov[2], riov; + struct server_slot *slot; + unsigned short offset; + + TRACE("in\n"); + + if((slot = lu_getslot(GET_INFO(f->f_dentry->d_sb))) == NULL) + return -ERESTARTSYS; + + if(lu_getname(f->f_dentry, slot->s_buf, LU_MAXDATA) < 0){ + WARN("lu_getname failed!\n"); + goto out; + } + + TRACE("reading %s, offset %u...\n", slot->s_buf, (unsigned)f->f_pos); + res = 0; + + switch((unsigned int)f->f_pos){ + + case 0: + if(filldir(dirent, ".", 1, 0, f->f_dentry->d_inode->i_ino, DT_DIR) < 0) + goto out; + f->f_pos++; + + case 1: + if(filldir(dirent, "..", 2, 1, f->f_dentry->d_parent->d_inode->i_ino, DT_DIR) < 0) + goto out; + f->f_pos++; + + default: + offset = f->f_pos; + siov[0].iov_base = &offset; + siov[0].iov_len = sizeof(unsigned short); + siov[1].iov_base = slot->s_buf; + siov[1].iov_len = strlen(slot->s_buf) + 1; + riov.iov_base = slot->s_buf; + riov.iov_len = LU_MAXDATA; + + if((res = lu_execute(GET_INFO(f->f_dentry->d_inode->i_sb), slot, PTYPE_READDIR, siov, 2, &riov, 1)) < 0){ + WARN("could not read directory content!\n"); + if(res == -ERESTARTSYS) + res = -EINTR; + goto out; + } + if(PIS_ERROR(res)){ + WARN("server failure!\n"); + res = PERROR(res); + goto out; + } + for(qname.name = slot->s_buf, c = strchr(slot->s_buf, '\n'); c != NULL; qname.name = c+1, c = strchr(c+1, '\n')){ + *c = 0; + TRACE("direntry: %s.\n", qname.name); + qname.len = strlen(qname.name); + if((ino = find_inode_number(f->f_dentry, &qname)) == 0) + ino = iunique(f->f_dentry->d_sb, 2); + if(filldir(dirent, qname.name, qname.len, f->f_pos, ino, DT_UNKNOWN) < 0) + break; + f->f_pos++; + } + } + + TRACE("out\n"); + out: + lu_putslot(slot); + return res; +} + +static struct dentry* lu_lookup(struct inode *dir, struct dentry *dentry) +{ + int res; + struct lufs_fattr fattr; + struct iovec siov, riov; + struct inode *inode; + struct server_slot *slot; + + TRACE("in\n"); + + if((slot = lu_getslot(GET_INFO(dir->i_sb))) == NULL) + return ERR_PTR(-ERESTARTSYS); + + if((res = lu_getname(dentry, slot->s_buf, LU_MAXDATA)) < 0){ + WARN("lu_getname failed!\n"); + goto out; + } + + TRACE("looking up %s\n", slot->s_buf); + + siov.iov_base = slot->s_buf; + siov.iov_len = strlen(slot->s_buf) + 1; + riov.iov_base = &fattr; + riov.iov_len = sizeof(struct lufs_fattr); + + if((res = lu_execute(GET_INFO(dir->i_sb), slot, PTYPE_STAT, &siov, 1, &riov, 1)) < 0) + goto out; + + if(PIS_ERROR(res)){ + TRACE("File not found...\n"); + dentry->d_op = &lufs_dentry_operations; + dentry->d_time = jiffies; + d_add(dentry, NULL); + lu_putslot(slot); + return NULL; + } + + lu_fixattrs(GET_INFO(dir->i_sb), &fattr); + + if(dentry == dentry->d_parent) + fattr.f_ino = 2; + else + fattr.f_ino = iunique(dentry->d_sb, 2); + + if((inode = lu_iget(dir->i_sb, &fattr))){ + dentry->d_op = &lufs_dentry_operations; + dentry->d_time = jiffies; + d_add(dentry, inode); + } + res = 0; + + out: + lu_putslot(slot); + + TRACE("out\n"); + return ERR_PTR(res); +} + +static int lu_instantiate(struct dentry *dentry, char *name, struct server_slot *slot) +{ + int res; + struct lufs_fattr fattr; + struct iovec siov, riov; + struct inode *inode; + + TRACE("in\n"); + + TRACE("instantiating %s\n", name); + + siov.iov_base = name; + siov.iov_len = strlen(name) + 1; + riov.iov_base = &fattr; + riov.iov_len = sizeof(struct lufs_fattr); + + if((res = lu_execute(GET_INFO(dentry->d_sb), slot, PTYPE_STAT, &siov, 1, &riov, 1)) < 0) + goto out; + + if(PIS_ERROR(res)){ + TRACE("File not found...\n"); + res = PERROR(res); + goto out; + } + + lu_fixattrs(GET_INFO(dentry->d_sb), &fattr); + + fattr.f_ino = iunique(dentry->d_sb, 2); + inode = lu_iget(dentry->d_sb, &fattr); + + if(!inode){ + res = -EACCES; + goto out; + } + + d_instantiate(dentry, inode); + res = 0; + + out: + TRACE("out\n"); + return res; +} + +static int lu_mkdir(struct inode *dir, struct dentry *dentry, int mode) +{ + int res; + struct server_slot *slot; + struct iovec iov[2]; + + TRACE("in\n"); + + if((slot = lu_getslot(GET_INFO(dentry->d_sb))) == NULL) + return -ERESTARTSYS; + + if((res = lu_getname(dentry, slot->s_buf, LU_MAXDATA)) < 0){ + WARN("lu_getname failed!\n"); + goto out; + } + + iov[0].iov_base = &mode; + iov[0].iov_len = sizeof(mode); + iov[1].iov_base = slot->s_buf; + iov[1].iov_len = strlen(slot->s_buf) + 1; + + if((res = lu_execute(GET_INFO(dentry->d_sb), slot, PTYPE_MKDIR, iov, 2, NULL, 0)) < 0) + goto out; + + if(PIS_ERROR(res)){ + TRACE("Could not create directory.\n"); + res = PERROR(res); + goto out; + } + + res = lu_instantiate(dentry, slot->s_buf, slot); + + out: + lu_putslot(slot); + + TRACE("out\n"); + return res; +} + +static int lu_create(struct inode *dir, struct dentry *dentry, int mode) +{ + int res; + struct server_slot *slot; + struct iovec iov[2]; + + TRACE("in\n"); + + if((slot = lu_getslot(GET_INFO(dentry->d_sb))) == NULL) + return -ERESTARTSYS; + + if((res = lu_getname(dentry, slot->s_buf, LU_MAXDATA)) < 0){ + WARN("lu_getname failed!\n"); + goto out; + } + + iov[0].iov_base = &mode; + iov[0].iov_len = sizeof(mode); + iov[1].iov_base = slot->s_buf; + iov[1].iov_len = strlen(slot->s_buf) + 1; + + if((res = lu_execute(GET_INFO(dentry->d_sb), slot, PTYPE_CREATE, iov, 2, NULL, 0)) < 0) + goto out; + + if(PIS_ERROR(res)){ + TRACE("Could not create file.\n"); + res = PERROR(res); + goto out; + } + + res = lu_instantiate(dentry, slot->s_buf, slot); + + out: + lu_putslot(slot); + + TRACE("out\n"); + return res; +} + +static int lu_rmdir(struct inode *dir, struct dentry *dentry) +{ + int res; + struct server_slot *slot; + struct iovec iov; + + if(!d_unhashed(dentry)) + return -EBUSY; + + TRACE("in\n"); + + if((slot = lu_getslot(GET_INFO(dentry->d_sb))) == NULL) + return -ERESTARTSYS; + + if((res = lu_getname(dentry, slot->s_buf, LU_MAXDATA)) < 0){ + WARN("lu_getname failed!"); + goto out; + } + + iov.iov_base = slot->s_buf; + iov.iov_len = strlen(slot->s_buf) + 1; + + if((res = lu_execute(GET_INFO(dentry->d_sb), slot, PTYPE_RMDIR, &iov, 1, NULL, 0)) < 0) + goto out; + + if(PIS_ERROR(res)){ + TRACE("rmdir failed!\n"); + res = PERROR(res); + goto out; + } + res = 0; + + out: + lu_putslot(slot); + + TRACE("out\n"); + return res; +} + +static int lu_rename(struct inode *old_dir, struct dentry *old_dentry, struct inode *new_dir, struct dentry *new_dentry) +{ + struct server_slot *slot; + int res; + struct iovec iov[2]; + + TRACE("in\n"); + + if((slot = lu_getslot(GET_INFO(old_dentry->d_sb))) == NULL) + return -ERESTARTSYS; + + if((res = lu_getname(old_dentry, slot->s_buf, LU_MAXPATHLEN)) < 0 || + (res = lu_getname(new_dentry, &(slot->s_buf[LU_MAXPATHLEN]), LU_MAXPATHLEN)) < 0){ + WARN("lu_getname failed!\n"); + goto out; + } + + iov[0].iov_base = slot->s_buf; + iov[0].iov_len = strlen(slot->s_buf) + 1; + iov[1].iov_base = &(slot->s_buf[LU_MAXPATHLEN]); + iov[1].iov_len = strlen(&(slot->s_buf[LU_MAXPATHLEN])) + 1; + + if((res = lu_execute(GET_INFO(old_dentry->d_sb), slot, PTYPE_RENAME, iov, 2, NULL, 0)) < 0) + goto out; + + if(PIS_ERROR(res)){ + TRACE("rename failed!\n"); + res = PERROR(res); + goto out; + } + res = 0; + + out: + lu_putslot(slot); + + TRACE("out\n"); + return res; +} + +static int lu_unlink(struct inode *dir, struct dentry *dentry) +{ + int res; + struct server_slot *slot; + struct iovec iov; + + TRACE("in\n"); + + if((slot = lu_getslot(GET_INFO(dentry->d_sb))) == NULL) + return -ERESTARTSYS; + + if((res = lu_getname(dentry, slot->s_buf, LU_MAXPATHLEN)) < 0){ + WARN("lu_getname failed!"); + goto out; + } + + iov.iov_base = slot->s_buf; + iov.iov_len = strlen(slot->s_buf) + 1; + + if((res = lu_execute(GET_INFO(dentry->d_sb), slot, PTYPE_UNLINK, &iov, 1, NULL, 0)) < 0) + goto out; + + if(PIS_ERROR(res)){ + TRACE("unlink failed!\n"); + res = PERROR(res); + goto out; + } + res = 0; + + out: + lu_putslot(slot); + + TRACE("out\n"); + return res; +} + + +static int lu_link(struct dentry *old_dentry, struct inode *dir, struct dentry *dentry) +{ + int res; + struct server_slot *slot; + struct iovec iov[2]; + + TRACE("in\n"); + + if(S_ISDIR(old_dentry->d_inode->i_mode)) + return -EPERM; + + if(!(slot = lu_getslot(GET_INFO(old_dentry->d_sb)))) + return -ERESTARTSYS; + + if((res = lu_getname(old_dentry, slot->s_buf, LU_MAXPATHLEN)) < 0){ + WARN("lu_getname failed!\n"); + goto out; + } + + if((res = lu_getname(dentry, &slot->s_buf[LU_MAXPATHLEN], LU_MAXPATHLEN)) < 0){ + WARN("lu_getname failed!\n"); + goto out; + } + + iov[0].iov_base = slot->s_buf; + iov[0].iov_len = strlen(slot->s_buf) + 1; + iov[1].iov_base = &slot->s_buf[LU_MAXPATHLEN]; + iov[1].iov_len = strlen(&slot->s_buf[LU_MAXPATHLEN]) + 1; + + d_drop(dentry); + + if((res = lu_execute(GET_INFO(old_dentry->d_sb), slot, PTYPE_LINK, iov, 2, NULL, 0)) < 0) + goto out; + + if(PIS_ERROR(res)){ + TRACE("link failed!\n"); + res = PERROR(res); + goto out; + } + + res = 0; + + out: + lu_putslot(slot); + TRACE("out\n"); + return res; +} + +static int lu_symlink(struct inode *dir, struct dentry *dentry, const char *symname) +{ + int res; + struct server_slot *slot; + struct iovec iov[2]; + + TRACE("in\n"); + TRACE("symlink: %s\n", symname); + + if(strlen(symname) > LU_MAXPATHLEN - 1) + return -ENAMETOOLONG; + + if(!(slot = lu_getslot(GET_INFO(dentry->d_sb)))) + return -ERESTARTSYS; + + if((res = lu_getname(dentry, slot->s_buf, LU_MAXPATHLEN)) < 0){ + WARN("lu_getname failed!\n"); + goto out; + } + + TRACE("fname: %s\n", slot->s_buf); + + strcpy(&slot->s_buf[LU_MAXPATHLEN], symname); + + iov[0].iov_base = slot->s_buf; + iov[0].iov_len = strlen(slot->s_buf) + 1; + iov[1].iov_base = &slot->s_buf[LU_MAXPATHLEN]; + iov[1].iov_len = strlen(&slot->s_buf[LU_MAXPATHLEN]) + 1; + + d_drop(dentry); + + if((res = lu_execute(GET_INFO(dentry->d_sb), slot, PTYPE_SYMLINK, iov, 2, NULL, 0)) < 0) + goto out; + + if(PIS_ERROR(res)){ + TRACE("symlink failed!\n"); + res = PERROR(res); + goto out; + } + + res = 0; + + out: + lu_putslot(slot); + TRACE("out\n"); + return res; +} + + + diff --git a/kernel/Linux/2.6/file.c b/kernel/Linux/2.6/file.c new file mode 100644 index 0000000..4441ef5 --- /dev/null +++ b/kernel/Linux/2.6/file.c @@ -0,0 +1,321 @@ +/* + * file.c + * Copyright (C) 2002 Florin Malita + * + * This file is part of LUFS, a free userspace filesystem implementation. + * See http://lufs.sourceforge.net/ for updates. + * + * LUFS 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. + * + * LUFS 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 + */ + +#include +#include +#include +#include +#include +#include + +#include +#include + +#include + +#include "lufs.h" +#include "proc.h" + +extern int lufs_notify_change(struct dentry*, struct iattr*); +extern int lu_revalidate_inode(struct dentry*); + +static int lu_file_open(struct inode *inode, struct file *file) +{ + int res, gres; + struct server_slot *slot; + struct iovec iov[2]; + unsigned flags; + + TRACE("in\n"); + + if((gres = generic_file_open(inode, file)) < 0) + return gres; + + TRACE("f_mode: %u, i_mode: %u\n", file->f_mode, inode->i_mode); + TRACE("f_flags: %u, i_flags: %u\n", file->f_flags, inode->i_flags); + + if((slot = lu_getslot(GET_INFO(file->f_dentry->d_sb))) == NULL) + return gres; + + if((res = lu_getname(file->f_dentry, slot->s_buf, LU_MAXDATA)) < 0){ + WARN("lu_getname failed!\n"); + goto out; + } + + flags = file->f_flags & O_ACCMODE; + iov[0].iov_base = &flags; + iov[0].iov_len = sizeof(flags); + iov[1].iov_base = slot->s_buf; + iov[1].iov_len = strlen(slot->s_buf) + 1; + + lu_execute(GET_INFO(file->f_dentry->d_sb), slot, PTYPE_OPEN, iov, 2, NULL, 0); + +out: + lu_putslot(slot); + + TRACE("out\n"); + return gres; +} + +static int lu_file_release(struct inode *inode, struct file *file) +{ + int res; + struct server_slot *slot; + struct iovec iov; + + TRACE("in\n"); + + if((slot = lu_getslot(GET_INFO(file->f_dentry->d_sb))) == NULL) + return -ERESTARTSYS; + + if((res = lu_getname(file->f_dentry, slot->s_buf, LU_MAXPATHLEN)) < 0){ + WARN("lu_getname failed!\n"); + goto out; + } + + iov.iov_base = slot->s_buf; + iov.iov_len = strlen(slot->s_buf) + 1; + + if((res = lu_execute(GET_INFO(file->f_dentry->d_sb), slot, PTYPE_RELEASE, &iov, 1, NULL, 0)) < 0) + goto out; + + if(PIS_ERROR(res)){ + TRACE("release failed\n"); + res = PERROR(res); + goto out; + } + + res = 0; + +out: + lu_putslot(slot); + + TRACE("out\n"); + return res; +} + +static int lu_file_readpage(struct file *f, struct page *p) +{ + int res; + struct iovec siov[3], riov; + long long offset; + unsigned long count; + struct server_slot *slot; + + TRACE("in\n"); + + if((slot = lu_getslot(GET_INFO(f->f_dentry->d_sb))) == NULL) + return -ERESTARTSYS; + + get_page(p); + + if((res = lu_getname(f->f_dentry, slot->s_buf, LU_MAXDATA)) < 0){ + WARN("lu_getname failed!\n"); + goto out; + } + + offset = p->index << PAGE_CACHE_SHIFT; + count = PAGE_SIZE; + + siov[0].iov_base = &offset; + siov[0].iov_len = sizeof(offset); + siov[1].iov_base = &count; + siov[1].iov_len = sizeof(count); + siov[2].iov_base = slot->s_buf; + siov[2].iov_len = strlen(slot->s_buf) + 1; + + riov.iov_base = page_address(p); + riov.iov_len = count; + + if((res = lu_execute(GET_INFO(f->f_dentry->d_sb), slot, PTYPE_READ, siov, 3, &riov, 1)) < 0) + goto out; + + if(PIS_ERROR(res)){ + TRACE("read failed\n"); + res = PERROR(res); + goto out; + } + + flush_dcache_page(p); + SetPageUptodate(p); + res = 0; + + out: + lu_putslot(slot); + unlock_page(p); + put_page(p); + + TRACE("out\n"); + return res; +} + +static int lu_file_writepage(struct page *p, struct writeback_control *wbc) +{ + TRACE("in\n"); + + TRACE("out\n"); + return -1; +} + +static int lu_file_preparewrite(struct file *f, struct page *p, unsigned offset, unsigned to) +{ + TRACE("in\n"); + + TRACE("out\n"); + + return 0; +} + +static int lu_file_commitwrite(struct file *f, struct page *p, unsigned offset, unsigned to) +{ + int res; + struct server_slot *slot; + struct iovec iov[4]; + char *buf; + long long off; + unsigned long cnt; + + TRACE("in\n"); + + if((slot = lu_getslot(GET_INFO(f->f_dentry->d_sb))) == NULL) + return -ERESTARTSYS; + + if((res = lu_getname(f->f_dentry, slot->s_buf, LU_MAXDATA)) < 0){ + WARN("lu_getname failed!\n"); + goto out2; + } + + lock_kernel(); + + buf = kmap(p) + offset; + cnt = to - offset; + off = offset + (((long long)p->index) << PAGE_CACHE_SHIFT); + + iov[0].iov_base = &off; + iov[0].iov_len = sizeof(off); + iov[1].iov_base = &cnt; + iov[1].iov_len = sizeof(cnt); + iov[2].iov_base = slot->s_buf; + iov[2].iov_len = strlen(slot->s_buf) + 1; + iov[3].iov_base = buf; + iov[3].iov_len = cnt; + + TRACE("write %s, offset %Ld, count %d\n", slot->s_buf, off, (int)cnt); + + if((res = lu_execute(GET_INFO(f->f_dentry->d_sb), slot, PTYPE_WRITE, iov, 4, NULL, 0)) < 0) + goto out1; + + + if(PIS_ERROR(res)){ + TRACE("write failed\n"); + res = PERROR(res); + goto out1; + } + + f->f_dentry->d_inode->i_mtime = f->f_dentry->d_inode->i_atime = CURRENT_TIME; + if(off + cnt > f->f_dentry->d_inode->i_size) + f->f_dentry->d_inode->i_size = off + cnt; + + res = cnt; + + out1: + kunmap(p); + unlock_kernel(); + out2: + lu_putslot(slot); + TRACE("out\n"); + return res; +} + +static int lu_file_read(struct file *filp, char *buf, size_t count, loff_t *ppos) +{ + struct dentry *dentry = filp->f_dentry; + int res; + + TRACE("in\n"); + + if(!(res = lu_revalidate_inode(dentry))) + res = generic_file_read(filp, buf, count, ppos); + + TRACE("out\n"); + + return res; +} + +static int lu_file_mmap(struct file *filp, struct vm_area_struct *vma) +{ + struct dentry *dentry = filp->f_dentry; + int res; + + TRACE("in\n"); + + if(!(res = lu_revalidate_inode(dentry))) + res = generic_file_mmap(filp, vma); + + TRACE("out\n"); + + return res; +} + +static ssize_t lu_file_write(struct file *filp, const char *buf, size_t count, loff_t *ppos) +{ + struct dentry *dentry = filp->f_dentry; + ssize_t res; + + TRACE("in\n"); + + if(!(res = lu_revalidate_inode(dentry)) && (count > 0)) + res = generic_file_write(filp, buf, count, ppos); + + TRACE("out\n"); + + return res; +} + +static int lu_file_fsync(struct file *filp, struct dentry *dentryp, int datasync) +{ + return 0; +} + +struct file_operations lu_file_operations = { + .llseek = generic_file_llseek, + .read = lu_file_read, + .write = lu_file_write, + .mmap = lu_file_mmap, + .open = lu_file_open, + .release = lu_file_release, + .fsync = lu_file_fsync, +}; + +struct inode_operations lu_file_inode_operations = { + .setattr = lufs_notify_change, +}; + +struct address_space_operations lu_file_aops = { + .readpage = lu_file_readpage, + .writepage = lu_file_writepage, + .prepare_write = lu_file_preparewrite, + .commit_write = lu_file_commitwrite, +}; + + + diff --git a/kernel/Linux/2.6/inode.c b/kernel/Linux/2.6/inode.c new file mode 100644 index 0000000..ee4f13f --- /dev/null +++ b/kernel/Linux/2.6/inode.c @@ -0,0 +1,535 @@ +/* + * inode.c + * Copyright (C) 2002-2003 Florin Malita + * + * This file is part of LUFS, a free userspace filesystem implementation. + * See http://lufs.sourceforge.net/ for updates. + * + * LUFS 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. + * + * LUFS 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 + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "lufs.h" +#include "proc.h" + +MODULE_AUTHOR("Florin Malita "); +MODULE_DESCRIPTION("Linux Userland Filesystem"); +#ifdef MODULE_LICENSE +MODULE_LICENSE("GPL"); +#endif + +extern struct file_operations lu_dir_operations, lu_file_operations; +extern struct inode_operations lu_dir_inode_operations, lu_file_inode_operations, lu_symlink_inode_operations; +extern struct address_space_operations lu_file_aops; +extern struct dentry_operations lufs_dentry_operations; + +static void lu_delete_inode(struct inode*); +static void lu_put_super(struct super_block*); +static int lu_statfs(struct super_block*, struct statfs*); + +static struct super_operations lu_sops = { + .drop_inode = generic_delete_inode, + .delete_inode = lu_delete_inode, + .put_super = lu_put_super, + .statfs = lu_statfs, +}; + + +/* + * Ignore unknown options, they're probably for the userspace daemon. + */ +static void parse_options(struct lufs_sb_info *server, char *opts) +{ + char *p, *q; + int len; + + if(!opts) + return; + + len = strlen(opts); + + while((p = strsep(&opts, ","))){ + if(strncmp(p, "server_socket=", 14) == 0){ + if(strlen(p+14) > UNIX_PATH_MAX) + goto ugly_opts; + strcpy(server->server_socket, p+14); + TRACE("server_socket: %s\n", server->server_socket); + }else + if(strncmp(p, "uid=", 4) == 0){ + if(current->uid) + ERROR("only root can use uid option!\n"); + else{ + if(strlen(p+4) > 5) + goto ugly_opts; + q = p + 4; + server->config.uid = simple_strtoul(q, &q, 0); + TRACE("uid: %d\n", server->config.uid); + } + }else + if(strncmp(p, "gid=", 4) == 0){ + if(current->uid) + ERROR("only root can use gid option!\n"); + else{ + if(strlen(p+4) > 5) + goto ugly_opts; + q = p + 4; + server->config.gid = simple_strtoul(q, &q, 0); + TRACE("gid: %d\n", server->config.gid); + } + }else + if(strncmp(p, "fmask=", 6) == 0){ + if(strlen(p + 6) > 3) + goto ugly_opts; + q = p + 6; + server->config.fmode = (((q[0] - '0') << 6) + ((q[1] - '0') << 3) + (q[2] - '0')) & (S_IRWXU | S_IRWXG | S_IRWXO); + TRACE("fmode: %d\n", server->config.fmode); + }else + if(strncmp(p, "dmask=", 6) == 0){ + if(strlen(p + 6) > 3) + goto ugly_opts; + q = p + 6; + server->config.dmode = (((q[0] - '0') << 6) + ((q[1] - '0') << 3) + (q[2] - '0')) & (S_IRWXU | S_IRWXG | S_IRWXO); + TRACE("dmode: %d\n", server->config.dmode); + }else + if(strncmp(p, "root=", 5) == 0){ + if(strlen(p+5) >= UNIX_PATH_MAX - 1) + goto ugly_opts; + strcpy(server->root, p+5); + server->rootlen = strlen(server->root); + + if(server->root[server->rootlen - 1] == '/'){ + server->root[server->rootlen - 1] = 0; + server->rootlen--; + } + + TRACE("remote root: %s, len: %u\n", server->root, server->rootlen); + }else + if(strncmp(p, "channels=", 9) == 0){ + if(strlen(p+9) > 5) + goto ugly_opts; + q = p + 9; + server->config.channels = simple_strtoul(q, &q, 0); + + TRACE("channels: %u\n", server->config.channels); + }else + if(strncmp(p, "own_fs", 6) == 0){ + server->config.own_fs = 1; + TRACE("forcing ownership\n"); + }else + if(strncmp(p, "server_pid=", 11) == 0){ + if(strlen(p+11) > 7) + goto ugly_opts; + q = p + 11; + server->server_pid = simple_strtoul(q, &q, 0); + + TRACE("server_pid: %u\n", server->server_pid); + } + } + + return; + + ugly_opts: + WARN("evil options!\n"); +} + +/* + * Fill in inode attributes. + * Ivalidate the page_cache pages if the inode has been modified. + */ +static void set_inode_attr(struct inode *inode, struct lufs_fattr *fattr) +{ + time_t last_time = inode->i_mtime.tv_sec; + loff_t last_sz = inode->i_size; + + TRACE("in\n"); + + inode->i_mode = fattr->f_mode; + inode->i_nlink = fattr->f_nlink; + inode->i_uid = fattr->f_uid; + inode->i_gid = fattr->f_gid; + inode->i_ctime.tv_sec = fattr->f_ctime; + inode->i_mtime.tv_sec = fattr->f_mtime; + inode->i_atime.tv_sec = fattr->f_atime; + inode->i_blksize = fattr->f_blksize; + inode->i_blocks = fattr->f_blocks; + inode->i_size = fattr->f_size; + + if(inode->i_mtime.tv_sec != last_time || inode->i_size != last_sz){ + TRACE("inode changed...\n"); + if(!S_ISDIR(inode->i_mode)) + invalidate_inode_pages(inode->i_mapping); + } + + TRACE("out\n"); +} + +static int lu_do_stat(struct dentry *dentry, struct lufs_fattr *fattr) +{ + struct server_slot *slot; + struct iovec siov, riov; + int res; + + TRACE("in\n"); + + if((slot = lu_getslot(GET_INFO(dentry->d_sb))) == NULL) + return -ERESTARTSYS; + + if((res = lu_getname(dentry, slot->s_buf, LU_MAXDATA)) < 0){ + WARN("lu_getname failed!\n"); + goto out; + } + + TRACE("stating %s...\n", slot->s_buf); + + siov.iov_base = slot->s_buf; + siov.iov_len = strlen(slot->s_buf) + 1; + riov.iov_base = fattr; + riov.iov_len = sizeof(struct lufs_fattr); + + if((res = lu_execute(GET_INFO(dentry->d_sb), slot, PTYPE_STAT, &siov, 1, &riov, 1)) < 0) + goto out; + + if(PIS_ERROR(res)){ + WARN("stat failed!\n"); + res = PERROR(res); + goto out; + } + + lu_fixattrs(GET_INFO(dentry->d_sb), fattr); + + res = 0; + + out: + TRACE("out\n"); + lu_putslot(slot); + return res; +} + +/* + * Reload inode attributes. + */ +static int lu_refresh_inode(struct dentry *dentry) +{ + struct inode *inode = dentry->d_inode; + struct lufs_fattr fattr; + int res; + + TRACE("in\n"); + + if((res = lu_do_stat(dentry, &fattr)) < 0) + return res; + + dentry->d_time = jiffies; + + if(!inode) + return 0; + + if((inode->i_mode & S_IFMT) == (fattr.f_mode & S_IFMT)) + set_inode_attr(inode, &fattr); + else{ + WARN("inode changed mode, %x to %x\n", inode->i_mode, (unsigned int)fattr.f_mode); + TRACE("oops!\n"); + + fattr.f_mode = inode->i_mode; + make_bad_inode(inode); + inode->i_mode = fattr.f_mode; + + if(!S_ISDIR(inode->i_mode)) + invalidate_inode_pages(inode->i_mapping); + + return -EIO; + } + + TRACE("out\n"); + return 0; +} + +int lu_revalidate_inode(struct dentry *dentry) +{ + int res = 0; + + TRACE("in\n"); + + lock_kernel(); + + if(time_before(jiffies, dentry->d_time + LU_MAXAGE)) + goto out; + + res = lu_refresh_inode(dentry); + + out: + TRACE("out\n"); + unlock_kernel(); + return res; +} + +int lufs_notify_change(struct dentry *dentry, struct iattr *iattr) +{ + struct server_slot *slot; + struct iovec iov[2]; + struct lufs_fattr fattr; + int res; + + TRACE("in\n"); + + if((res = lu_do_stat(dentry, &fattr)) < 0) + return res; + + if((slot = lu_getslot(GET_INFO(dentry->d_sb))) == NULL) + return -ERESTARTSYS; + + if((res = lu_getname(dentry, slot->s_buf, LU_MAXDATA)) < 0){ + WARN("lu_getname failed!\n"); + goto out; + } + + if(iattr->ia_valid & ATTR_MODE) + fattr.f_mode = iattr->ia_mode; + if(iattr->ia_valid & ATTR_UID) + fattr.f_uid = iattr->ia_uid; + if(iattr->ia_valid & ATTR_GID) + fattr.f_gid = iattr->ia_gid; + if(iattr->ia_valid & ATTR_SIZE) + fattr.f_size = iattr->ia_size; + if(iattr->ia_valid & ATTR_ATIME) + fattr.f_atime= iattr->ia_atime.tv_sec; + if(iattr->ia_valid & ATTR_MTIME) + fattr.f_mtime= iattr->ia_mtime.tv_sec; + if(iattr->ia_valid & ATTR_CTIME) + fattr.f_ctime= iattr->ia_ctime.tv_sec; + + iov[0].iov_base = &fattr; + iov[0].iov_len = sizeof(struct lufs_fattr); + iov[1].iov_base = slot->s_buf; + iov[1].iov_len = strlen(slot->s_buf) + 1; + + if((res = lu_execute(GET_INFO(dentry->d_sb), slot, PTYPE_SETATTR, iov, 2, NULL, 0)) < 0) + goto out; + + if(PIS_ERROR(res)){ + WARN("setattr failed!\n"); + res = PERROR(res); + goto out; + } + + res = 0; + + lu_refresh_inode(dentry); + + out: + TRACE("out\n"); + lu_putslot(slot); + return res; +} + +/* + * We always create a new inode here. + */ +struct inode* lu_iget(struct super_block *sb, struct lufs_fattr *fattr) +{ + struct inode *res; + + TRACE("in\n"); + + res = new_inode(sb); + if(!res) + return NULL; + res->i_ino = fattr->f_ino; + set_inode_attr(res, fattr); + + if(S_ISDIR(res->i_mode)){ + TRACE("it's a dir.\n"); + res->i_op = &lu_dir_inode_operations; + res->i_fop = &lu_dir_operations; + }else if(S_ISLNK(res->i_mode)){ + TRACE("it's a link.\n"); + res->i_op = &lu_symlink_inode_operations; + }else{ + TRACE("it's a file.\n"); + res->i_op = &lu_file_inode_operations; + res->i_fop = &lu_file_operations; + res->i_data.a_ops = &lu_file_aops; + } + + insert_inode_hash(res); + return res; +} + +static int lu_statfs(struct super_block *sb, struct statfs *attr) +{ + TRACE("in\n"); + + attr->f_type = LU_MAGIC; + attr->f_bsize = LU_BLOCKSIZE; + attr->f_blocks = 0; + attr->f_namelen = LU_MAXPATHLEN; + attr->f_files = -1; + attr->f_bavail = -1; + + TRACE("out\n"); + return 0; +} + +static void lu_put_super(struct super_block *sb) +{ + struct siginfo info; + + TRACE("in\n"); + + info.si_signo = SIGUSR1; + info.si_errno = 0; + info.si_code = SI_USER; + info.si_pid = current->pid; + info.si_uid = current->uid; + + /* notify the daemon that we're going bye-bye */ + kill_proc_info(SIGUSR1, &info, GET_INFO(sb)->server_pid); + + lu_empty_slots(GET_INFO(sb)); + kfree(GET_INFO(sb)); + TRACE("out\n"); +} + +static void lu_delete_inode(struct inode *in) +{ + TRACE("in\n"); + clear_inode(in); + TRACE("out\n"); +} + +static int lu_fill_super(struct super_block *sb, void *opts, int silent) +{ + struct lufs_sb_info *info; + struct server_slot *slot; + struct lufs_fattr root_attr; + struct inode *root_inode; + + int i; + + TRACE("in\n"); + + if(!opts){ + ERROR("need some options here!\n"); + goto out; + } + + if((info = (struct lufs_sb_info*)kmalloc(sizeof(struct lufs_sb_info), GFP_KERNEL)) == NULL){ + ERROR("kmalloc error!\n"); + goto out; + } + memset(info, 0, sizeof(struct lufs_sb_info)); + info->lock = RW_LOCK_UNLOCKED; + INIT_LIST_HEAD(&info->slots); + + info->config.uid = current->uid; + info->config.gid = current->gid; + info->config.channels = LU_NRSLOTS; + + parse_options(info, opts); + + if(!info->server_socket[0]){ + ERROR("no server_socket specified!\n"); + goto out_info; + } + + for(i = 0; i < info->config.channels; i++){ + if((slot = kmalloc(sizeof(struct server_slot), GFP_KERNEL)) == NULL){ + ERROR("kmalloc error!\n"); + goto out_slots; + } + memset(slot, 0, sizeof(struct server_slot)); + init_MUTEX(&slot->s_lock); + if((slot->s_buf = kmalloc(LU_MAXDATA, GFP_KERNEL)) == NULL){ + ERROR("kmalloc error!\n"); + goto out_slots; + } + list_add(&slot->s_list, &info->slots); + } + + sb->s_fs_info = info; + sb->s_blocksize = LU_BLOCKSIZE; + sb->s_blocksize_bits = LU_BLOCKSIZEBITS; + sb->s_magic = LU_MAGIC; + sb->s_op = &lu_sops; + sb->s_flags = 0; + sb->s_maxbytes = ((((long long)1) << 32) << LU_BLOCKSIZEBITS) - 1; + TRACE("sb->s_maxbytes=%Ld\n",sb->s_maxbytes); + + lu_lookup_root(info, &root_attr); + root_inode = lu_iget(sb, &root_attr); + if(!root_inode) + goto out_slots; + sb->s_root = d_alloc_root(root_inode); + if(!sb->s_root) + goto out_slots; + + sb->s_root->d_op = &lufs_dentry_operations; + sb->s_root->d_time = jiffies; + + TRACE("mount succeded: %s\n", info->server_socket); + return 0; + + out_slots: + lu_empty_slots(info); + out_info: + kfree(info); + out: + ERROR("mount failed!\n"); + return -EINVAL; +} + +static struct super_block *lu_get_sb(struct file_system_type *fs_type, int flags, char *dev_name, void *data) +{ + return get_sb_nodev(fs_type, flags, data, lu_fill_super); +} + +static struct file_system_type lu_fs_type = { + .owner = THIS_MODULE, + .name = "lufs", + .get_sb = lu_get_sb, + .kill_sb = kill_anon_super, +}; + +static int __init lu_init(void) +{ + VERBOSE("UserLand File System\n"); + VERBOSE("Copyright (c) 2002, Florin Malita\n"); + return register_filesystem(&lu_fs_type); +} + +static void __exit lu_release(void) +{ + VERBOSE("Unregistering lufs...\n"); + unregister_filesystem(&lu_fs_type); +} + +module_init(lu_init); +module_exit(lu_release); diff --git a/kernel/Linux/2.6/lufs.h b/kernel/Linux/2.6/lufs.h new file mode 100644 index 0000000..1275099 --- /dev/null +++ b/kernel/Linux/2.6/lufs.h @@ -0,0 +1,87 @@ +/* + * lufs.h + * Copyright (C) 2002 Florin Malita + * + * This file is part of LUFS, a free userspace filesystem implementation. + * See http://lufs.sourceforge.net/ for updates. + * + * LUFS 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. + * + * LUFS 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 _LUFS_H_ +#define _LUFS_H_ + +#include +#include +#include + +#include "../../../include/lufs/proto.h" + +#undef TRACE +#undef WARN +#undef VERBOSE +#undef ERROR + +#ifdef LUFS_DEBUG +#define TRACE(x...) do { printk(KERN_INFO "(%s) - ", __func__); printk(x); } while(0) +#define WARN(x...) do { printk(KERN_ERR "(%s) - ", __func__); printk(x); } while(0) +#else +#define TRACE(x...) do {} while(0) +#define WARN(x...) do {} while(0) +#endif + +#ifdef LUFS_VERBOSE +#define VERBOSE(x...) do { printk(KERN_INFO "(%s) - ", __func__); printk(x); } while(0) +#else +#define VERBOSE(x...) do {} while(0) +#endif + +#define ERROR(x...) do { printk(KERN_ERR "(%s) - ", __func__); printk(x); } while(0) + +#define GET_INFO(sb) ((struct lufs_sb_info*)sb->s_fs_info) + +#define LU_MAXPATHLEN 1024 +#define LU_MAXTRIES 10 +#define LU_MAXIOVEC 5 +#define LU_NRSLOTS 3 +#define LU_MAGIC 0xfade +#define LU_MAXAGE HZ*5 + +#define LU_DEF_UID 2 +#define LU_DEF_GID 2 + +#define LU_BLOCKSIZE 512 +#define LU_BLOCKSIZEBITS 9 + +struct lufs_config{ + __kernel_uid_t uid; + __kernel_gid_t gid; + __kernel_mode_t fmode; + __kernel_mode_t dmode; + unsigned channels; + int own_fs; +}; + +struct lufs_sb_info{ + struct list_head slots; + struct lufs_config config; + rwlock_t lock; + char server_socket[UNIX_PATH_MAX]; + pid_t server_pid; + char root[UNIX_PATH_MAX]; + unsigned rootlen; +}; + +#endif diff --git a/kernel/Linux/2.6/proc.c b/kernel/Linux/2.6/proc.c new file mode 100644 index 0000000..cb0b2e7 --- /dev/null +++ b/kernel/Linux/2.6/proc.c @@ -0,0 +1,505 @@ +/* + * proc.c + * Copyright (C) 2002 Florin Malita + * + * This file is part of LUFS, a free userspace filesystem implementation. + * See http://lufs.sourceforge.net/ for updates. + * + * LUFS 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. + * + * LUFS 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 + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "lufs.h" +#include "proc.h" + +static int sock_send(struct socket *sock, struct iovec *iov, int len) +{ + struct msghdr msg = { + .msg_name = NULL, + .msg_namelen = 0, + .msg_iov = iov, + .msg_iovlen = len, + .msg_control = NULL, + .msg_controllen = 0, + .msg_flags = 0 + }; + int res, i, size; + mm_segment_t fs; + + for(i = 0, size = 0; i < len; i++) + size += iov[i].iov_len; + + fs = get_fs(); + set_fs(get_ds()); + res = sock_sendmsg(sock, &msg, size); + set_fs(fs); + + return res; +} + +static int sock_recv(struct socket *sock, struct iovec *iov, int len, int rsize, unsigned flags) +{ + struct msghdr msg = { + .msg_flags = flags, + .msg_name = NULL, + .msg_namelen = 0, + .msg_iov = iov, + .msg_iovlen = len, + .msg_control = NULL, + .msg_controllen = 0 + }; + mm_segment_t fs; + int res, i, size; + + for(i = 0, size = 0; i < len; i++) + size += iov[i].iov_len; + + if(size < rsize){ + VERBOSE("Trying to overflow old me?! Truncating...\n"); + rsize = size; + } + + fs = get_fs(); + set_fs(get_ds()); + res = sock_recvmsg(sock, &msg, rsize, flags); + set_fs(fs); + + return res; +} + +static int sock_connect(char *path, struct socket **s) +{ + struct sockaddr_un addr; + int res; + + if(strlen(path) > UNIX_PATH_MAX - 1){ + WARN("unix domain path too long: %s", path); + return -1; + } + + addr.sun_family = AF_UNIX; + strcpy(addr.sun_path, path); + + if((res = sock_create(PF_UNIX, SOCK_STREAM, 0, s)) < 0){ + WARN("failed to create a unix domain socket!\n"); + return res; + } + + if((res = (*s)->ops->connect(*s, (struct sockaddr*)&addr, sizeof(addr), 0)) < 0){ + WARN("failed to connect the socket: %d!\n", res); + return res; + } + return 0; +} + +static int slot_reconnect(struct lufs_sb_info *info, struct server_slot *slot) +{ + int res = 0, tries = 0; + + if(slot->s_sock){ + TRACE("closing socket.\n"); + sock_release(slot->s_sock); + slot->s_sock = NULL; + } + + while(tries++ < LU_MAXTRIES && (res = sock_connect(info->server_socket, &slot->s_sock)) < 0){ + TRACE("retrying...\n"); + sock_release(slot->s_sock); + slot->s_sock = NULL; + } + + if(res >= 0){ + TRACE("successfully reconnected.\n"); + } + + return res; +} + +void lu_empty_slots(struct lufs_sb_info *info) +{ + struct server_slot *slot; + + while(!list_empty(&info->slots)){ + slot = list_entry(info->slots.next, struct server_slot, s_list); + if(slot->s_sock) + sock_release(slot->s_sock); + list_del(&slot->s_list); + if(slot->s_buf) + kfree(slot->s_buf); + kfree(slot); + } +} + +static int do_execute(struct socket *sock, unsigned short cmd, unsigned short msglen, struct iovec *siov, unsigned short slen, struct iovec *riov, unsigned short rlen) +{ + struct lu_msg msg; + struct iovec iov; + int res; + + TRACE("msg_len: %d\n", msglen); + + msg.msg_version = PVERSION; + msg.msg_type = cmd; + msg.msg_datalen = msglen; + msg.msg_pid = current->pid; + + iov.iov_base = &msg; + iov.iov_len = sizeof(struct lu_msg); + + if((res = sock_send(sock, &iov, 1)) < 0){ + WARN("sock_send failed!\n"); + return res; + } + if((res = sock_send(sock, siov, slen)) < 0){ + WARN("sock_send failed!\n"); + return res; + } + + iov.iov_base = &msg; + iov.iov_len = sizeof(struct lu_msg); + if((res = sock_recv(sock, &iov, 1, sizeof(struct lu_msg), 0)) < 0){ + WARN("sock_recv failed!\n"); + return res; + } + if(res != sizeof(struct lu_msg)){ + WARN("Ayeeee, didn't read a whole header!\n"); + return -EBUSY; + } + + if((msg.msg_datalen == 0)) + return msg.msg_type; + + if(riov == NULL){ + WARN("Unexpected data!!! Getting out of sync...\n"); + return -1; + } + + if((res = sock_recv(sock, riov, rlen, msg.msg_datalen, 0)) < 0){ + WARN("sock_recv failed!\n"); + return res; + } + + return msg.msg_type; +} + +struct server_slot* lu_getslot(struct lufs_sb_info *info) +{ + struct list_head *p, *nd_best = NULL; + struct server_slot *slot; + int gotlock = 0; + + /* Look for a slot used by this process before */ + read_lock(&info->lock); + list_for_each(p, &info->slots) + if(list_entry(p, struct server_slot, s_list)->s_lastpid == current->pid){ + TRACE("found a previous used slot for %u.\n", current->pid); + if(down_trylock(&list_entry(p, struct server_slot, s_list)->s_lock) == 0){ + gotlock = 1; + break; + } + TRACE("oops! I still hold the lock! forget this one...\n"); + }else + if(!nd_best){ + nd_best = p; + } + + /* if we couldn't find one, take the first not locked by us */ + if(p == &info->slots){ + if(!nd_best){ + ERROR("deadlock: all locks owned by us!\n"); + read_unlock(&info->lock); + return NULL; + }else + p = nd_best; + + } + read_unlock(&info->lock); + + slot = list_entry(p, struct server_slot, s_list); + + /* Get the lock on that slot */ + if(!gotlock) + if(down_interruptible(&slot->s_lock)) + return NULL; + + slot->s_lastpid = current->pid; + + /* Move it to the tail */ + write_lock(&info->lock); + list_del(p); + list_add_tail(p, &info->slots); + write_unlock(&info->lock); + + return slot; +} + +void lu_putslot(struct server_slot *slot) +{ + up(&slot->s_lock); +} + +int lu_execute(struct lufs_sb_info *info, struct server_slot *slot, unsigned short cmd, struct iovec *siov, unsigned short slen, struct iovec *riov, unsigned short rlen) +{ + int res, i, msglen; + struct iovec bkup[LU_MAXIOVEC]; + + for(i = 0, msglen = 0; i < slen; i++){ + bkup[i] = siov[i]; + msglen += siov[i].iov_len; + } + + if(slot->s_sock == NULL){ + TRACE("slot not connected.\n"); + if((res = slot_reconnect(info, slot)) < 0){ + ERROR("failed to connect!\n"); + goto out; + } + } + + if((res = do_execute(slot->s_sock, cmd, msglen, siov, slen, riov, rlen)) < 0){ + TRACE("do_execute failed!\n"); + + if(signal_pending(current) && (!sigismember(¤t->pending.signal, SIGPIPE))){ + TRACE("interrupted by a signal. disconnecting this slot...\n"); + sock_release(slot->s_sock); + slot->s_sock = NULL; + goto out; + } + + if(sigismember(¤t->pending.signal, SIGPIPE)){ + TRACE("got a SIGPIPE\n"); + sigdelset(¤t->pending.signal, SIGPIPE); + } + + if((res = slot_reconnect(info, slot)) < 0){ + ERROR("could't reconnect!\n"); + goto out; + } + + for(i = 0; i < slen; i++) + siov[i] = bkup[i]; + + if((res = do_execute(slot->s_sock, cmd, msglen, siov, slen, riov, rlen)) < 0){ + ERROR("error executing command!\n"); + goto out; + } + } + + out: + return res; +} + +int lu_getname(struct dentry *d, char *name, int max) +{ + int len = 0; + struct dentry *p; + struct lufs_sb_info *info = GET_INFO(d->d_sb); + + for(p = d; p != p->d_parent; p = p->d_parent) + len += p->d_name.len + 1; + + TRACE("root: %s, rootlen: %d, namelen: %d\n", info->root, info->rootlen, len); + + if(len + info->rootlen > max) + return -1; + + strcpy(name, info->root); + + if(len + info->rootlen == 0){ + strcat(name, "/"); + goto out; + } + + len += info->rootlen; + + name[len] = 0; + for(p = d; p != p->d_parent; p = p->d_parent){ + len -= p->d_name.len; + strncpy(&(name[len]), p->d_name.name, p->d_name.len); + name[--len] = '/'; + } + +out: + TRACE("name resolved to %s\n", name); + return 0; +} + +int lu_getname_dumb(struct dentry *d, char *name, int max) +{ + int len = 0; + struct dentry *p; + + for(p = d; p != p->d_parent; p = p->d_parent) + len += p->d_name.len + 1; + + if(len > max) + return -1; + + if(len == 0){ + name[0] = '/'; + name[1] = 0; + goto out; + } + + name[len] = 0; + for(p = d; p != p->d_parent; p = p->d_parent){ + len -= p->d_name.len; + strncpy(&(name[len]), p->d_name.name, p->d_name.len); + name[--len] = '/'; + } + +out: + return 0; +} + +static void init_root_dirent(struct lufs_sb_info *server, struct lufs_fattr *fattr) +{ + memset(fattr, 0, sizeof(struct lufs_fattr)); + fattr->f_nlink = 1; + fattr->f_uid = server->config.uid; + fattr->f_gid = server->config.gid; + fattr->f_blksize = 512; + fattr->f_ino = 2; + fattr->f_mtime = CURRENT_TIME.tv_sec; + fattr->f_mode = S_IRUSR | S_IRGRP | S_IROTH | S_IXUSR | S_IXGRP | S_IXOTH | S_IFDIR | server->config.dmode; + fattr->f_size = 512; + fattr->f_blocks = 1; +} + +void lu_lookup_root(struct lufs_sb_info *server, struct lufs_fattr *fattr) +{ + struct server_slot *slot; + struct iovec siov, riov; + int res; + + TRACE("in\n"); + + if((slot = lu_getslot(server)) == NULL){ + init_root_dirent(server, fattr); + return; + } + + if(server->rootlen) + strcpy(slot->s_buf, server->root); + else + strcpy(slot->s_buf, "/"); + + TRACE("stating root %s\n", slot->s_buf); + + siov.iov_base = slot->s_buf; + siov.iov_len = strlen(slot->s_buf) + 1; + riov.iov_base = fattr; + riov.iov_len = sizeof(struct lufs_fattr); + + if((res = lu_execute(server, slot, PTYPE_STAT, &siov, 1, &riov, 1)) < 0){ + init_root_dirent(server, fattr); + goto out; + } + + if(PIS_ERROR(res)){ + WARN("stat failed!\n"); + init_root_dirent(server, fattr); + goto out; + } + + lu_fixattrs(server, fattr); + + fattr->f_ino = 2; + + out: + TRACE("out\n"); + lu_putslot(slot); +} + +void lu_fixattrs(struct lufs_sb_info *info, struct lufs_fattr *fattr) +{ + + fattr->f_blksize = LU_BLOCKSIZE; + + if(S_ISREG(fattr->f_mode) || S_ISDIR(fattr->f_mode)) + fattr->f_blocks = (fattr->f_size + LU_BLOCKSIZE - 1) / LU_BLOCKSIZE; + else + fattr->f_blocks = 0; + + if(info->config.own_fs){ + + if(!fattr->f_uid) + fattr->f_mode = (fattr->f_mode & ~S_IRWXU) | ((fattr->f_mode & S_IRWXO)*(S_IRWXU/S_IRWXO)); + + if(!fattr->f_gid) + fattr->f_mode = (fattr->f_mode & ~S_IRWXG) | ((fattr->f_mode & S_IRWXO)*(S_IRWXG/S_IRWXO)); + + fattr->f_uid = info->config.uid; + fattr->f_gid = info->config.gid; + + }else{ + + if(fattr->f_uid) + fattr->f_uid = info->config.uid; + else + fattr->f_uid = LU_DEF_UID; + + if(fattr->f_gid) + fattr->f_gid = info->config.gid; + else + fattr->f_gid = LU_DEF_GID; + } + + if(fattr->f_mode & S_IFDIR) + fattr->f_mode |= info->config.dmode; + else + fattr->f_mode |= info->config.fmode; +} + +void lu_xlate_symlink(char *link, char *target, char *buf) +{ + int i; + char *c1, *c2 = link; + + TRACE("translating %s->%s\n", link, target); + + for(c1 = strchr(link, '/'); c1 && !strncmp(link, target, c1 - link); c2 = c1, c1 = strchr(c1 + 1, '/')); + + TRACE("disjoint paths: %s, %s\n", c2, target + (c2 - link)); + + for(i = 0, c1 = c2; (c1 = strchr(c1 + 1, '/')); i++); + + strcpy(buf, "./"); + + for(; i > 0; i--) + strcat(buf, "../"); + + strcat(buf, target + (c2 - link) + 1); + + TRACE("absolute link resolved to %s\n", buf); + +} + diff --git a/kernel/Linux/2.6/proc.h b/kernel/Linux/2.6/proc.h new file mode 100644 index 0000000..83a598d --- /dev/null +++ b/kernel/Linux/2.6/proc.h @@ -0,0 +1,51 @@ +/* + * proc.h + * Copyright (C) 2002 Florin Malita + * + * This file is part of LUFS, a free userspace filesystem implementation. + * See http://lufs.sourceforge.net/ for updates. + * + * LUFS 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. + * + * LUFS 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 _LU_PROC_H_ +#define _LU_PROC_H_ + +#include +#include +#include + +struct server_slot{ + struct socket *s_sock; + struct semaphore s_lock; + struct list_head s_list; + pid_t s_lastpid; + char *s_buf; +}; + +struct lufs_fattr; + +int lu_execute(struct lufs_sb_info*, struct server_slot*, unsigned short, struct iovec*, unsigned short, struct iovec*, unsigned short); +void lu_empty_slots(struct lufs_sb_info*); +int lu_getname(struct dentry*, char*, int); +int lu_getname_dumb(struct dentry*, char*, int); +struct server_slot* lu_getslot(struct lufs_sb_info*); +void lu_putslot(struct server_slot*); +int lu_revalidate_inode(struct dentry*); +void lu_lookup_root(struct lufs_sb_info*, struct lufs_fattr*); +void lu_fixattrs(struct lufs_sb_info*, struct lufs_fattr*); +void lu_xlate_symlink(char*, char*, char*); + +#endif diff --git a/kernel/Linux/2.6/symlink.c b/kernel/Linux/2.6/symlink.c new file mode 100644 index 0000000..c60570b --- /dev/null +++ b/kernel/Linux/2.6/symlink.c @@ -0,0 +1,184 @@ +/* + * symlink.c + * Copyright (C) 2002 Florin Malita + * + * This file is part of LUFS, a free userspace filesystem implementation. + * See http://lufs.sourceforge.net/ for updates. + * + * LUFS 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. + * + * LUFS 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 + */ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + + +#include "lufs.h" +#include "proc.h" + +static char failed_link[] = "invalid"; + +static int lu_readlink(struct dentry *dentry, char *buffer, int bufflen) +{ + struct server_slot *slot; + struct iovec siov, riov; + int res; + char *cc = failed_link; + + TRACE("in\n"); + + if((slot = lu_getslot(GET_INFO(dentry->d_sb))) == NULL) + return vfs_readlink(dentry, buffer, bufflen, cc); + + if((res = lu_getname(dentry, slot->s_buf, LU_MAXDATA)) < 0){ + WARN("lu_getname failed!\n"); + goto out; + } + + siov.iov_base = slot->s_buf; + siov.iov_len = strlen(slot->s_buf) + 1; + riov.iov_base = &slot->s_buf[LU_MAXPATHLEN]; + riov.iov_len = LU_MAXPATHLEN; + + if((res = lu_execute(GET_INFO(dentry->d_sb), slot, PTYPE_READLINK, &siov, 1, &riov, 1)) < 0) + goto out; + + if(PIS_ERROR(res)){ + TRACE("read_link failed.\n"); + res = PERROR(res); + goto out; + } + + cc = &slot->s_buf[LU_MAXPATHLEN]; + + TRACE("response: %s\n", cc); + + if(*cc == '/'){ + if(GET_INFO(dentry->d_sb)->rootlen){ + if(strncmp(GET_INFO(dentry->d_sb)->root, cc, GET_INFO(dentry->d_sb)->rootlen)){ + WARN("symlink outside mounted root!"); + cc = failed_link; + goto out; + } + cc += GET_INFO(dentry->d_sb)->rootlen; + } + + lu_xlate_symlink(slot->s_buf, slot->s_buf + LU_MAXPATHLEN, slot->s_buf); + + cc = slot->s_buf; + + } + + + + out: + res = vfs_readlink(dentry, buffer, bufflen, cc); + + lu_putslot(slot); + + TRACE("out\n"); + return res; +} + +static int lu_followlink(struct dentry *dentry, struct nameidata *nd) +{ + struct server_slot *slot; + struct iovec siov, riov; + int res; + char *cc = failed_link; + char *tmp; + + TRACE("in\n"); + + if((slot = lu_getslot(GET_INFO(dentry->d_sb))) == NULL) + return vfs_follow_link(nd, cc); + + + if((res = lu_getname(dentry, slot->s_buf, LU_MAXDATA)) < 0){ + WARN("lu_getname failed!\n"); + goto out; + } + + siov.iov_base = slot->s_buf; + siov.iov_len = strlen(slot->s_buf) + 1; + riov.iov_base = &slot->s_buf[LU_MAXPATHLEN]; + riov.iov_len = LU_MAXPATHLEN; + + if((res = lu_execute(GET_INFO(dentry->d_sb), slot, PTYPE_READLINK, &siov, 1, &riov, 1)) < 0) + goto out; + + if(PIS_ERROR(res)){ + TRACE("read_link failed.\n"); + res = PERROR(res); + goto out; + } + + cc = &slot->s_buf[LU_MAXPATHLEN]; + + if(*cc == '/'){ + if(GET_INFO(dentry->d_sb)->rootlen){ + if(strncmp(GET_INFO(dentry->d_sb)->root, cc, GET_INFO(dentry->d_sb)->rootlen)){ + WARN("symlink outside mounted root!"); + cc = failed_link; + goto out; + } + cc += GET_INFO(dentry->d_sb)->rootlen; + } + + lu_xlate_symlink(slot->s_buf, slot->s_buf + LU_MAXPATHLEN, slot->s_buf); + + cc = slot->s_buf; + + } + + out: + + /* vfs_follow_link somehow manages to call lookup_validate, so we need to + release the slot, in case it's the only one, otherwise lu_lookup will + fail (avoid a deadlock). bad, bad vfs_follow_link! you break the overall + beauty of no kmallocs... */ + + if((tmp = kmalloc(strlen(cc) + 1, GFP_KERNEL)) == NULL){ + WARN("out of mem!\n"); + tmp = failed_link; + }else + strcpy(tmp, cc); + + lu_putslot(slot); + res = vfs_follow_link(nd, tmp); + + if(tmp != failed_link) + kfree(tmp); + + TRACE("out\n"); + return res; +} + +struct inode_operations lu_symlink_inode_operations = { + .readlink = lu_readlink, + .follow_link = lu_followlink, +}; + + + + + -- 1.8.3.1