patch-2.4.20 linux-2.4.20/fs/intermezzo/dir.c
Next file: linux-2.4.20/fs/intermezzo/ext_attr.c
Previous file: linux-2.4.20/fs/intermezzo/dcache.c
Back to the patch index
Back to the overall index
- Lines: 1484
- Date:
Thu Nov 28 15:53:15 2002
- Orig file:
linux-2.4.19/fs/intermezzo/dir.c
- Orig date:
Mon Feb 25 11:38:08 2002
diff -urN linux-2.4.19/fs/intermezzo/dir.c linux-2.4.20/fs/intermezzo/dir.c
@@ -1,14 +1,27 @@
-/*
- *
+/* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
+ * vim:expandtab:shiftwidth=8:tabstop=8:
*
* Copyright (C) 2000 Stelias Computing, Inc.
* Copyright (C) 2000 Red Hat, Inc.
* Copyright (C) 2000 Tacitus Systems
* Copyright (C) 2000 Peter J. Braam
*
+ * This file is part of InterMezzo, http://www.inter-mezzo.org.
+ *
+ * InterMezzo is free software; you can redistribute it and/or
+ * modify it under the terms of version 2 of the GNU General Public
+ * License as published by the Free Software Foundation.
+ *
+ * InterMezzo 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 InterMezzo; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
-
#include <stdarg.h>
#include <asm/bitops.h>
@@ -31,39 +44,38 @@
#include <linux/module.h>
#include <linux/intermezzo_fs.h>
-#include <linux/intermezzo_upcall.h>
#include <linux/intermezzo_psdev.h>
static inline void presto_relock_sem(struct inode *dir)
{
- /* the lock from sys_mkdir / lookup_create */
- down(&dir->i_sem);
- /* the rest is done by the do_{create,mkdir, ...} */
+ /* the lock from sys_mkdir / lookup_create */
+ down(&dir->i_sem);
+ /* the rest is done by the do_{create,mkdir, ...} */
}
static inline void presto_relock_other(struct inode *dir)
{
- /* vfs_mkdir locks */
+ /* vfs_mkdir locks */
down(&dir->i_zombie);
- lock_kernel();
+ lock_kernel();
}
static inline void presto_fulllock(struct inode *dir)
{
- /* the lock from sys_mkdir / lookup_create */
- down(&dir->i_sem);
- /* vfs_mkdir locks */
+ /* the lock from sys_mkdir / lookup_create */
+ down(&dir->i_sem);
+ /* vfs_mkdir locks */
down(&dir->i_zombie);
- lock_kernel();
+ lock_kernel();
}
static inline void presto_unlock(struct inode *dir)
{
- /* vfs_mkdir locks */
- unlock_kernel();
+ /* vfs_mkdir locks */
+ unlock_kernel();
up(&dir->i_zombie);
- /* the lock from sys_mkdir / lookup_create */
- up(&dir->i_sem);
+ /* the lock from sys_mkdir / lookup_create */
+ up(&dir->i_sem);
}
@@ -71,116 +83,83 @@
* these are initialized in super.c
*/
extern int presto_permission(struct inode *inode, int mask);
-int presto_ilookup_uid = 0;
-
-extern int presto_prep(struct dentry *, struct presto_cache **,
- struct presto_file_set **);
+static int izo_authorized_uid = 0;
-static int dentry2id(struct dentry *dentry, ino_t *id, unsigned int *generation)
+int izo_dentry_is_ilookup(struct dentry *dentry, ino_t *id,
+ unsigned int *generation)
{
- char *tmpname;
+ char tmpname[64];
char *next;
- int error = 0;
ENTRY;
- if (dentry->d_name.len > EXT2_NAME_LEN) {
- EXIT;
- return -ENAMETOOLONG;
- }
-
/* prefix is 7 characters: '...ino:' */
- if ( dentry->d_name.len < 7 ||
+ if ( dentry->d_name.len < 7 || dentry->d_name.len > 64 ||
memcmp(dentry->d_name.name, PRESTO_ILOOKUP_MAGIC, 7) != 0 ) {
EXIT;
- return 1;
- }
-
- PRESTO_ALLOC(tmpname, char *, dentry->d_name.len - 7 + 1);
- if ( !tmpname ) {
- EXIT;
- return -ENOMEM;
+ return 0;
}
memcpy(tmpname, dentry->d_name.name + 7, dentry->d_name.len - 7);
- *(tmpname + dentry->d_name.len) = '\0';
+ *(tmpname + dentry->d_name.len - 7) = '\0';
- /* name is of the form <inode number>:<generation> */
- *id = simple_strtoul(tmpname, &next, 0);
+ /* name is of the form ...ino:<inode number>:<generation> */
+ *id = simple_strtoul(tmpname, &next, 16);
if ( *next == PRESTO_ILOOKUP_SEP ) {
- *generation = simple_strtoul(next + 1, 0, 0);
- CDEBUG(D_INODE, "INO to find = %s\n", tmpname);
- CDEBUG(D_INODE, "Id = %lx (%lu), generation %x (%d)\n",
- *id, *id, *generation, *generation);
- } else
- error = 1;
-
- PRESTO_FREE(tmpname, dentry->d_name.len - 7 + 1);
- EXIT;
- return error;
+ *generation = simple_strtoul(next + 1, 0, 16);
+ CDEBUG(D_INODE, "ino string: %s, Id = %lx (%lu), "
+ "generation %x (%d)\n",
+ tmpname, *id, *id, *generation, *generation);
+ EXIT;
+ return 1;
+ } else {
+ EXIT;
+ return 0;
+ }
}
-static int presto_opendir_upcall(int minor, struct dentry *de,
- struct dentry *root, int async)
+struct dentry *presto_tmpfs_ilookup(struct inode *dir,
+ struct dentry *dentry,
+ ino_t ino,
+ unsigned int generation)
{
- int rc;
- char *path, *buffer;
- int pathlen;
-
- PRESTO_ALLOC(buffer, char *, PAGE_SIZE);
- if ( !buffer ) {
- printk("PRESTO: out of memory!\n");
- return ENOMEM;
- }
- path = presto_path(de, root, buffer, PAGE_SIZE);
- pathlen = MYPATHLEN(buffer, path);
- CDEBUG(D_INODE, "path: %*s, len %d\n", pathlen, path, pathlen);
- rc = lento_opendir(minor, pathlen, path, async);
- PRESTO_FREE(buffer, PAGE_SIZE);
- return rc;
+ return dentry;
}
+
inline int presto_can_ilookup(void)
{
- return (current->euid == presto_ilookup_uid ||
+ return (current->euid == izo_authorized_uid ||
capable(CAP_DAC_READ_SEARCH));
}
-struct dentry *presto_ilookup(struct inode *dir, struct dentry *dentry,
- ino_t ino, unsigned int generation)
+struct dentry *presto_iget_ilookup(struct inode *dir,
+ struct dentry *dentry,
+ ino_t ino,
+ unsigned int generation)
{
struct inode *inode;
int error;
ENTRY;
- /* if we can't ilookup, forbid anything with this name to
- * avoid any security issues/name clashes.
- */
if ( !presto_can_ilookup() ) {
- CDEBUG(D_CACHE, "ilookup denied: euid %u, ilookup_uid %u\n",
- current->euid, presto_ilookup_uid);
- EXIT;
+ CERROR("ilookup denied: euid %u, authorized_uid %u\n",
+ current->euid, izo_authorized_uid);
return ERR_PTR(-EPERM);
}
+ error = -ENOENT;
inode = iget(dir->i_sb, ino);
- if (!inode || !inode->i_nlink || is_bad_inode(inode)) {
- CDEBUG(D_PIOCTL, "fatal: invalid inode %ld (%s).\n",
- ino, inode ? inode->i_nlink ? "bad inode" :
- "no links" : "NULL");
- error = -ENOENT;
- EXIT;
+ if (!inode) {
+ CERROR("fatal: NULL inode ino %lu\n", ino);
+ goto cleanup_iput;
+ }
+ if (is_bad_inode(inode) || inode->i_nlink == 0) {
+ CERROR("fatal: bad inode ino %lu, links %d\n", ino, inode->i_nlink);
goto cleanup_iput;
}
-
- /* We need to make sure we have the right inode (by checking the
- * generation) so we don't write into the wrong file (old inode was
- * deleted and then a new one was created with the same number).
- */
if (inode->i_generation != generation) {
- CDEBUG(D_PIOCTL, "fatal: bad generation %u (want %u)\n",
+ CERROR("fatal: bad generation %u (want %u)\n",
inode->i_generation, generation);
- error = -ENOENT;
- EXIT;
goto cleanup_iput;
}
@@ -196,73 +175,164 @@
return ERR_PTR(error);
}
+struct dentry *presto_add_ilookup_dentry(struct dentry *parent,
+ struct dentry *real)
+{
+ struct inode *inode = real->d_inode;
+ struct dentry *de;
+ char buf[32];
+ char *ptr = buf;
+ struct dentry *inodir;
+ struct presto_dentry_data *dd;
+
+ inodir = lookup_one_len("..iopen..", parent, strlen("..iopen.."));
+ if (!inodir || IS_ERR(inodir) || !inodir->d_inode ) {
+ CERROR("%s: bad ..iopen.. lookup\n", __FUNCTION__);
+ return NULL;
+ }
+ inodir->d_inode->i_op = &presto_dir_iops;
+
+ snprintf(ptr, 32, "...ino:%lx:%x", inode->i_ino, inode->i_generation);
+
+ de = lookup_one_len(ptr, inodir, strlen(ptr));
+ if (!de || IS_ERR(de)) {
+ CERROR("%s: bad ...ino lookup %ld\n",
+ __FUNCTION__, PTR_ERR(de));
+ dput(inodir);
+ return NULL;
+ }
+
+ dd = presto_d2d(real);
+ if (!dd)
+ BUG();
+
+ /* already exists */
+ if (de->d_inode)
+ BUG();
+#if 0
+ if (de->d_inode != inode ) {
+ CERROR("XX de->d_inode %ld, inode %ld\n",
+ de->d_inode->i_ino, inode->i_ino);
+ BUG();
+ }
+ if (dd->dd_inodentry) {
+ CERROR("inodentry exists %ld \n", inode->i_ino);
+ BUG();
+ }
+ dput(inodir);
+ return de;
+ }
+#endif
+
+ if (presto_d2d(de))
+ BUG();
+
+ atomic_inc(&inode->i_count);
+ de->d_op = &presto_dentry_ops;
+ d_add(de, inode);
+ if (!de->d_op)
+ CERROR("DD: no ops dentry %p, dd %p\n", de, dd);
+ dd->dd_inodentry = de;
+ dd->dd_count++;
+ de->d_fsdata = dd;
+
+ dput(inodir);
+ return de;
+}
struct dentry *presto_lookup(struct inode * dir, struct dentry *dentry)
{
int rc = 0;
struct dentry *de;
struct presto_cache *cache;
- struct presto_file_set *fset;
- int error;
int minor;
ino_t ino;
unsigned int generation;
+ struct inode_operations *iops;
+ int is_ilookup = 0;
ENTRY;
- error = presto_prep(dentry->d_parent, &cache, &fset);
- if ( error ) {
+ cache = presto_get_cache(dir);
+ if (cache == NULL) {
+ CERROR("InterMezzo BUG: no cache in presto_lookup "
+ "(dir ino: %ld)!\n", dir->i_ino);
EXIT;
- return ERR_PTR(error);
+ return NULL;
}
minor = presto_c2m(cache);
- CDEBUG(D_CACHE, "dir ino: %ld, name: %*s\n",
- dir->i_ino, dentry->d_name.len, dentry->d_name.name);
- if ( ISLENTO(minor) )
- CDEBUG(D_CACHE, "We are lento\n");
-
- rc = dentry2id(dentry, &ino, &generation);
- CDEBUG(D_CACHE, "dentry2id returned %d\n", rc);
- if ( rc < 0 ) {
- EXIT;
- goto exit;
+ iops = filter_c2cdiops(cache->cache_filter);
+ if (!iops || !iops->lookup) {
+ CERROR("InterMezzo BUG: filesystem has no lookup\n");
+ EXIT;
+ return NULL;
}
- if ( rc == 0 ) {
- de = presto_ilookup(dir, dentry, ino, generation);
- } else {
- struct inode_operations *iops = filter_c2cdiops(cache->cache_filter);
- rc = 0;
- /* recursively do a cache lookup in dir */
- if (iops && iops->lookup)
+
+ CDEBUG(D_CACHE, "dentry %p, dir ino: %ld, name: %*s, islento: %d\n",
+ dentry, dir->i_ino, dentry->d_name.len, dentry->d_name.name,
+ ISLENTO(minor));
+
+ if (dentry->d_fsdata)
+ CERROR("DD -- BAD dentry %p has data\n", dentry);
+
+ dentry->d_fsdata = NULL;
+#if 0
+ if (ext2_check_for_iopen(dir, dentry))
+ de = NULL;
+ else {
+#endif
+ if ( izo_dentry_is_ilookup(dentry, &ino, &generation) ) {
+ de = cache->cache_filter->o_trops->tr_ilookup
+ (dir, dentry, ino, generation);
+ is_ilookup = 1;
+ } else
de = iops->lookup(dir, dentry);
- else {
- printk("filesystem has no lookup\n");
- EXIT;
- goto exit;
- }
+#if 0
}
- /* XXX this needs some work to handle returning de if we get it */
- filter_setup_dentry_ops(cache->cache_filter,
+#endif
+
+ if ( IS_ERR(de) ) {
+ CERROR("dentry lookup error %ld\n", PTR_ERR(de));
+ return de;
+ }
+
+ /* some file systems have no read_inode: set methods here */
+ if (dentry->d_inode)
+ presto_set_ops(dentry->d_inode, cache->cache_filter);
+
+ filter_setup_dentry_ops(cache->cache_filter,
dentry->d_op, &presto_dentry_ops);
dentry->d_op = filter_c2udops(cache->cache_filter);
- if ( IS_ERR(de) ) {
- rc = PTR_ERR(de);
- CDEBUG(D_CACHE, "dentry lookup error %d\n", rc);
- EXIT;
- goto exit;
+
+ /* In lookup we will tolerate EROFS return codes from presto_set_dd
+ * to placate NFS. EROFS indicates that a fileset was not found but
+ * we should still be able to continue through a lookup.
+ * Anything else is a hard error and must be returned to VFS. */
+ if (!is_ilookup)
+ rc = presto_set_dd(dentry);
+ if (rc && rc != -EROFS) {
+ CERROR("presto_set_dd failed (dir %ld, name %*s): %d\n",
+ dir->i_ino, dentry->d_name.len, dentry->d_name.name, rc);
+ return ERR_PTR(rc);
}
- /* some file systems set the methods in lookup, not in
- read_inode, as a result we should set the methods here
- as well as in read_inode
- */
- if (dentry->d_inode) {
- presto_set_ops(dentry->d_inode, cache->cache_filter);
- }
EXIT;
-exit:
- return ERR_PTR(rc);
+ return NULL;
+}
+
+static inline int presto_check_set_fsdata (struct dentry *de)
+{
+ if (presto_d2d(de) == NULL) {
+#ifdef PRESTO_NO_NFS
+ CERROR("dentry without fsdata: %p: %*s\n", de,
+ de->d_name.len, de->d_name.name);
+ BUG();
+#endif
+ return presto_set_dd (de);
+ }
+
+ return 0;
}
int presto_setattr(struct dentry *de, struct iattr *iattr)
@@ -273,6 +343,7 @@
struct lento_vfs_context info = { 0, 0, 0 };
ENTRY;
+
error = presto_prep(de, &cache, &fset);
if ( error ) {
EXIT;
@@ -295,7 +366,7 @@
if (!ISLENTO(presto_c2m(cache)))
info.flags = LENTO_FL_KML;
- info.flags |= LENTO_FL_IGNORE_TIME;
+ info.flags |= LENTO_FL_IGNORE_TIME;
error = presto_do_setattr(fset, de, iattr, &info);
presto_put_permit(de->d_inode);
return error;
@@ -310,23 +381,32 @@
int presto_prep(struct dentry *dentry, struct presto_cache **cache,
struct presto_file_set **fset)
-{
+{
+ int rc;
+
+ /* NFS might pass us dentries which have not gone through lookup.
+ * Test and set d_fsdata for such dentries
+ */
+ rc = presto_check_set_fsdata (dentry);
+ if (rc) return rc;
+
*fset = presto_fset(dentry);
- if ( !*fset ) {
- CDEBUG(D_INODE, "No file set for dentry at %p\n", dentry);
+ if ( *fset == NULL ) {
+ CERROR("No file set for dentry at %p: %*s\n", dentry,
+ dentry->d_name.len, dentry->d_name.name);
return -EROFS;
}
*cache = (*fset)->fset_cache;
- if ( !*cache ) {
- printk("PRESTO: BAD, BAD: cannot find cache\n");
+ if ( *cache == NULL ) {
+ CERROR("PRESTO: BAD, BAD: cannot find cache\n");
return -EBADF;
}
CDEBUG(D_PIOCTL, "---> cache flags %x, fset flags %x\n",
(*cache)->cache_flags, (*fset)->fset_flags);
if( presto_is_read_only(*fset) ) {
- printk("PRESTO: cannot modify read-only fileset, minor %d.\n",
+ CERROR("PRESTO: cannot modify read-only fileset, minor %d.\n",
presto_c2m(*cache));
return -EROFS;
}
@@ -342,12 +422,18 @@
struct presto_file_set *fset;
ENTRY;
+ error = presto_check_set_fsdata(dentry);
+ if ( error ) {
+ EXIT;
+ return error;
+ }
+
error = presto_prep(dentry->d_parent, &cache, &fset);
if ( error ) {
EXIT;
return error;
}
- presto_unlock(dir);
+ presto_unlock(dir);
/* Does blocking and non-blocking behavious need to be
checked for. Without blocking (return 1), the permit
@@ -360,12 +446,13 @@
}
presto_relock_sem(dir);
- parent = dentry->d_parent;
+ parent = dentry->d_parent;
memset(&info, 0, sizeof(info));
if (!ISLENTO(presto_c2m(cache)))
info.flags = LENTO_FL_KML;
- info.flags |= LENTO_FL_IGNORE_TIME;
+ info.flags |= LENTO_FL_IGNORE_TIME;
error = presto_do_create(fset, parent, dentry, mode, &info);
+
presto_relock_other(dir);
presto_put_permit(dir);
EXIT;
@@ -388,6 +475,12 @@
return error;
}
+ error = presto_check_set_fsdata(new_dentry);
+ if ( error ) {
+ EXIT;
+ return error;
+ }
+
error = presto_prep(new_dentry->d_parent, &new_cache, &new_fset);
if ( error ) {
EXIT;
@@ -412,15 +505,25 @@
return -EROFS;
}
- presto_relock_sem(dir);
+ presto_relock_sem(dir);
parent = new_dentry->d_parent;
memset(&info, 0, sizeof(info));
if (!ISLENTO(presto_c2m(cache)))
info.flags = LENTO_FL_KML;
- info.flags |= LENTO_FL_IGNORE_TIME;
+ info.flags |= LENTO_FL_IGNORE_TIME;
error = presto_do_link(fset, old_dentry, parent,
new_dentry, &info);
+
+#if 0
+ /* XXX for links this is not right */
+ if (cache->cache_filter->o_trops->tr_add_ilookup ) {
+ struct dentry *d;
+ d = cache->cache_filter->o_trops->tr_add_ilookup
+ (dir->i_sb->s_root, new_dentry, 1);
+ }
+#endif
+
presto_relock_other(dir);
presto_put_permit(dir);
presto_put_permit(old_dentry->d_inode);
@@ -437,13 +540,19 @@
ENTRY;
+ error = presto_check_set_fsdata(dentry);
+ if ( error ) {
+ EXIT;
+ return error;
+ }
+
error = presto_prep(dentry->d_parent, &cache, &fset);
if ( error ) {
EXIT;
return error;
}
- presto_unlock(dir);
+ presto_unlock(dir);
if ( presto_get_permit(dir) < 0 ) {
EXIT;
@@ -454,17 +563,18 @@
memset(&info, 0, sizeof(info));
if (!ISLENTO(presto_c2m(cache)))
info.flags = LENTO_FL_KML;
- info.flags |= LENTO_FL_IGNORE_TIME;
+ info.flags |= LENTO_FL_IGNORE_TIME;
- presto_relock_sem(dir);
- parent = dentry->d_parent;
+ presto_relock_sem(dir);
+ parent = dentry->d_parent;
error = presto_do_mkdir(fset, parent, dentry, mode, &info);
- presto_relock_other(dir);
+ presto_relock_other(dir);
presto_put_permit(dir);
return error;
}
+
static int presto_symlink(struct inode *dir, struct dentry *dentry,
const char *name)
{
@@ -475,6 +585,12 @@
struct lento_vfs_context info;
ENTRY;
+ error = presto_check_set_fsdata(dentry);
+ if ( error ) {
+ EXIT;
+ return error;
+ }
+
error = presto_prep(dentry->d_parent, &cache, &fset);
if ( error ) {
EXIT;
@@ -484,16 +600,16 @@
presto_unlock(dir);
if ( presto_get_permit(dir) < 0 ) {
EXIT;
- presto_fulllock(dir);
+ presto_fulllock(dir);
return -EROFS;
}
- presto_relock_sem(dir);
+ presto_relock_sem(dir);
parent = dentry->d_parent;
memset(&info, 0, sizeof(info));
if (!ISLENTO(presto_c2m(cache)))
info.flags = LENTO_FL_KML;
- info.flags |= LENTO_FL_IGNORE_TIME;
+ info.flags |= LENTO_FL_IGNORE_TIME;
error = presto_do_symlink(fset, parent, dentry, name, &info);
presto_relock_other(dir);
presto_put_permit(dir);
@@ -509,6 +625,12 @@
struct lento_vfs_context info;
ENTRY;
+ error = presto_check_set_fsdata(dentry);
+ if ( error ) {
+ EXIT;
+ return error;
+ }
+
error = presto_prep(dentry->d_parent, &cache, &fset);
if ( error ) {
EXIT;
@@ -518,17 +640,19 @@
presto_unlock(dir);
if ( presto_get_permit(dir) < 0 ) {
EXIT;
- presto_fulllock(dir);
+ presto_fulllock(dir);
return -EROFS;
}
- presto_relock_sem(dir);
+ presto_relock_sem(dir);
parent = dentry->d_parent;
memset(&info, 0, sizeof(info));
if (!ISLENTO(presto_c2m(cache)))
info.flags = LENTO_FL_KML;
- info.flags |= LENTO_FL_IGNORE_TIME;
+ info.flags |= LENTO_FL_IGNORE_TIME;
+
error = presto_do_unlink(fset, parent, dentry, &info);
+
presto_relock_other(dir);
presto_put_permit(dir);
return error;
@@ -544,6 +668,13 @@
ENTRY;
CDEBUG(D_FILE, "prepping presto\n");
+ error = presto_check_set_fsdata(dentry);
+
+ if ( error ) {
+ EXIT;
+ return error;
+ }
+
error = presto_prep(dentry->d_parent, &cache, &fset);
if ( error ) {
EXIT;
@@ -554,32 +685,32 @@
/* We need to dget() before the dput in double_unlock, to ensure we
* still have dentry references. double_lock doesn't do dget for us.
*/
- unlock_kernel();
- if (d_unhashed(dentry))
- d_rehash(dentry);
+ unlock_kernel();
+ if (d_unhashed(dentry))
+ d_rehash(dentry);
double_up(&dir->i_zombie, &dentry->d_inode->i_zombie);
double_up(&dir->i_sem, &dentry->d_inode->i_sem);
CDEBUG(D_FILE, "getting permit\n");
if ( presto_get_permit(parent->d_inode) < 0 ) {
EXIT;
- double_down(&dir->i_sem, &dentry->d_inode->i_sem);
- double_down(&dir->i_zombie, &dentry->d_inode->i_zombie);
-
- lock_kernel();
+ double_down(&dir->i_sem, &dentry->d_inode->i_sem);
+ double_down(&dir->i_zombie, &dentry->d_inode->i_zombie);
+
+ lock_kernel();
return -EROFS;
}
CDEBUG(D_FILE, "locking\n");
- double_down(&dir->i_sem, &dentry->d_inode->i_sem);
- parent = dentry->d_parent;
+ double_down(&dir->i_sem, &dentry->d_inode->i_sem);
+ parent = dentry->d_parent;
memset(&info, 0, sizeof(info));
if (!ISLENTO(presto_c2m(cache)))
info.flags = LENTO_FL_KML;
- info.flags |= LENTO_FL_IGNORE_TIME;
+ info.flags |= LENTO_FL_IGNORE_TIME;
error = presto_do_rmdir(fset, parent, dentry, &info);
presto_put_permit(parent->d_inode);
- lock_kernel();
+ lock_kernel();
EXIT;
return error;
}
@@ -593,6 +724,12 @@
struct lento_vfs_context info;
ENTRY;
+ error = presto_check_set_fsdata(dentry);
+ if ( error ) {
+ EXIT;
+ return error;
+ }
+
error = presto_prep(dentry->d_parent, &cache, &fset);
if ( error ) {
EXIT;
@@ -605,13 +742,13 @@
presto_fulllock(dir);
return -EROFS;
}
-
- presto_relock_sem(dir);
+
+ presto_relock_sem(dir);
parent = dentry->d_parent;
memset(&info, 0, sizeof(info));
if (!ISLENTO(presto_c2m(cache)))
info.flags = LENTO_FL_KML;
- info.flags |= LENTO_FL_IGNORE_TIME;
+ info.flags |= LENTO_FL_IGNORE_TIME;
error = presto_do_mknod(fset, parent, dentry, mode, rdev, &info);
presto_relock_other(dir);
presto_put_permit(dir);
@@ -620,80 +757,81 @@
}
inline void presto_triple_unlock(struct inode *old_dir, struct inode *new_dir,
- struct dentry *old_dentry,
- struct dentry *new_dentry, int triple)
+ struct dentry *old_dentry,
+ struct dentry *new_dentry, int triple)
{
- /* rename_dir case */
- if (S_ISDIR(old_dentry->d_inode->i_mode)) {
- if (triple) {
- triple_up(&old_dir->i_zombie,
- &new_dir->i_zombie,
- &new_dentry->d_inode->i_zombie);
- } else {
- double_up(&old_dir->i_zombie,
- &new_dir->i_zombie);
- }
- up(&old_dir->i_sb->s_vfs_rename_sem);
- } else /* this case is rename_other */
- double_up(&old_dir->i_zombie, &new_dir->i_zombie);
- /* done by do_rename */
- unlock_kernel();
- double_up(&old_dir->i_sem, &new_dir->i_sem);
+ /* rename_dir case */
+ if (S_ISDIR(old_dentry->d_inode->i_mode)) {
+ if (triple) {
+ triple_up(&old_dir->i_zombie,
+ &new_dir->i_zombie,
+ &new_dentry->d_inode->i_zombie);
+ } else {
+ double_up(&old_dir->i_zombie,
+ &new_dir->i_zombie);
+ }
+ up(&old_dir->i_sb->s_vfs_rename_sem);
+ } else /* this case is rename_other */
+ double_up(&old_dir->i_zombie, &new_dir->i_zombie);
+ /* done by do_rename */
+ unlock_kernel();
+ double_up(&old_dir->i_sem, &new_dir->i_sem);
}
inline void presto_triple_fulllock(struct inode *old_dir,
- struct inode *new_dir,
- struct dentry *old_dentry,
- struct dentry *new_dentry, int triple)
-{
- /* done by do_rename */
- double_down(&old_dir->i_sem, &new_dir->i_sem);
- lock_kernel();
- /* rename_dir case */
- if (S_ISDIR(old_dentry->d_inode->i_mode)) {
- down(&old_dir->i_sb->s_vfs_rename_sem);
- if (triple) {
- triple_down(&old_dir->i_zombie,
- &new_dir->i_zombie,
- &new_dentry->d_inode->i_zombie);
- } else {
- double_down(&old_dir->i_zombie,
- &new_dir->i_zombie);
- }
- } else /* this case is rename_other */
- double_down(&old_dir->i_zombie, &new_dir->i_zombie);
+ struct inode *new_dir,
+ struct dentry *old_dentry,
+ struct dentry *new_dentry, int triple)
+{
+ /* done by do_rename */
+ double_down(&old_dir->i_sem, &new_dir->i_sem);
+ lock_kernel();
+ /* rename_dir case */
+ if (S_ISDIR(old_dentry->d_inode->i_mode)) {
+ down(&old_dir->i_sb->s_vfs_rename_sem);
+ if (triple) {
+ triple_down(&old_dir->i_zombie,
+ &new_dir->i_zombie,
+ &new_dentry->d_inode->i_zombie);
+ } else {
+ double_down(&old_dir->i_zombie,
+ &new_dir->i_zombie);
+ }
+ } else /* this case is rename_other */
+ double_down(&old_dir->i_zombie, &new_dir->i_zombie);
}
inline void presto_triple_relock_sem(struct inode *old_dir,
- struct inode *new_dir,
- struct dentry *old_dentry,
- struct dentry *new_dentry, int triple)
-{
- /* done by do_rename */
- double_down(&old_dir->i_sem, &new_dir->i_sem);
- lock_kernel();
+ struct inode *new_dir,
+ struct dentry *old_dentry,
+ struct dentry *new_dentry, int triple)
+{
+ /* done by do_rename */
+ double_down(&old_dir->i_sem, &new_dir->i_sem);
+ lock_kernel();
}
inline void presto_triple_relock_other(struct inode *old_dir,
- struct inode *new_dir,
- struct dentry *old_dentry,
- struct dentry *new_dentry, int triple)
-{
- /* rename_dir case */
- if (S_ISDIR(old_dentry->d_inode->i_mode)) {
- down(&old_dir->i_sb->s_vfs_rename_sem);
- if (triple) {
- triple_down(&old_dir->i_zombie,
- &new_dir->i_zombie,
- &new_dentry->d_inode->i_zombie);
- } else {
- double_down(&old_dir->i_zombie,
- &new_dir->i_zombie);
- }
- } else /* this case is rename_other */
- double_down(&old_dir->i_zombie, &new_dir->i_zombie);
+ struct inode *new_dir,
+ struct dentry *old_dentry,
+ struct dentry *new_dentry, int triple)
+{
+ /* rename_dir case */
+ if (S_ISDIR(old_dentry->d_inode->i_mode)) {
+ down(&old_dir->i_sb->s_vfs_rename_sem);
+ if (triple) {
+ triple_down(&old_dir->i_zombie,
+ &new_dir->i_zombie,
+ &new_dentry->d_inode->i_zombie);
+ } else {
+ double_down(&old_dir->i_zombie,
+ &new_dir->i_zombie);
+ }
+ } else /* this case is rename_other */
+ double_down(&old_dir->i_zombie, &new_dir->i_zombie);
}
+
// XXX this can be optimized: renamtes across filesets only require
// multiple KML records, but can locally be executed normally.
int presto_rename(struct inode *old_dir, struct dentry *old_dentry,
@@ -713,7 +851,6 @@
EXIT;
return error;
}
-
error = presto_prep(new_parent, &new_cache, &new_fset);
if ( error ) {
EXIT;
@@ -732,27 +869,27 @@
triple = (S_ISDIR(old_dentry->d_inode->i_mode) && new_dentry->d_inode)?
1:0;
- presto_triple_unlock(old_dir, new_dir, old_dentry, new_dentry, triple);
+ presto_triple_unlock(old_dir, new_dir, old_dentry, new_dentry, triple);
if ( presto_get_permit(old_dir) < 0 ) {
EXIT;
- presto_triple_fulllock(old_dir, new_dir, old_dentry, new_dentry, triple);
+ presto_triple_fulllock(old_dir, new_dir, old_dentry, new_dentry, triple);
return -EROFS;
}
if ( presto_get_permit(new_dir) < 0 ) {
EXIT;
- presto_triple_fulllock(old_dir, new_dir, old_dentry, new_dentry, triple);
+ presto_triple_fulllock(old_dir, new_dir, old_dentry, new_dentry, triple);
return -EROFS;
}
- presto_triple_relock_sem(old_dir, new_dir, old_dentry, new_dentry, triple);
+ presto_triple_relock_sem(old_dir, new_dir, old_dentry, new_dentry, triple);
memset(&info, 0, sizeof(info));
if (!ISLENTO(presto_c2m(cache)))
info.flags = LENTO_FL_KML;
- info.flags |= LENTO_FL_IGNORE_TIME;
- error = presto_do_rename(fset, old_parent, old_dentry, new_parent,
- new_dentry, &info);
- presto_triple_relock_other(old_dir, new_dir, old_dentry, new_dentry, triple);
+ info.flags |= LENTO_FL_IGNORE_TIME;
+ error = do_rename(fset, old_parent, old_dentry, new_parent,
+ new_dentry, &info);
+ presto_triple_relock_other(old_dir, new_dir, old_dentry, new_dentry, triple);
presto_put_permit(new_dir);
presto_put_permit(old_dir);
@@ -812,72 +949,467 @@
}
-static int presto_dir_open(struct inode *inode, struct file *file)
+int presto_ioctl(struct inode *inode, struct file *file,
+ unsigned int cmd, unsigned long arg)
{
- int rc = 0;
- struct dentry *de = file->f_dentry;
- struct file_operations *fops;
- struct presto_cache *cache;
- struct presto_file_set *fset;
- int minor;
- int error;
+ char buf[1024];
+ struct izo_ioctl_data *data = NULL;
+ struct presto_dentry_data *dd;
+ int rc;
ENTRY;
- error = presto_prep(file->f_dentry, &cache, &fset);
- if ( error ) {
+ /* Try the filesystem's ioctl first, and return if it succeeded. */
+ dd = presto_d2d(file->f_dentry);
+ if (dd && dd->dd_fset) {
+ int (*cache_ioctl)(struct inode *, struct file *, unsigned int, unsigned long ) = filter_c2cdfops(dd->dd_fset->fset_cache->cache_filter)->ioctl;
+ rc = -ENOTTY;
+ if (cache_ioctl)
+ rc = cache_ioctl(inode, file, cmd, arg);
+ if (rc != -ENOTTY) {
+ EXIT;
+ return rc;
+ }
+ }
+
+ if (current->euid != 0 && current->euid != izo_authorized_uid) {
EXIT;
- make_bad_inode(inode);
- return error;
+ return -EPERM;
}
- minor = presto_c2m(cache);
- CDEBUG(D_CACHE, "minor %d, DATA_OK: %d, ino: %ld\n",
- minor, presto_chk(de, PRESTO_DATA), inode->i_ino);
+ memset(buf, 0, sizeof(buf));
+
+ if (izo_ioctl_getdata(buf, buf + 1024, (void *)arg)) {
+ CERROR("intermezzo ioctl: data error\n");
+ return -EINVAL;
+ }
+ data = (struct izo_ioctl_data *)buf;
+
+ switch(cmd) {
+ case IZO_IOC_REINTKML: {
+ int rc;
+ int cperr;
+ rc = kml_reint_rec(file, data);
+
+ EXIT;
+ cperr = copy_to_user((char *)arg, data, sizeof(*data));
+ if (cperr) {
+ CERROR("WARNING: cperr %d\n", cperr);
+ rc = -EFAULT;
+ }
+ return rc;
+ }
+
+ case IZO_IOC_GET_RCVD: {
+ struct izo_rcvd_rec rec;
+ struct presto_file_set *fset;
+ int rc;
+
+ fset = presto_fset(file->f_dentry);
+ if (fset == NULL) {
+ EXIT;
+ return -ENODEV;
+ }
+ rc = izo_rcvd_get(&rec, fset, data->ioc_uuid);
+ if (rc < 0) {
+ EXIT;
+ return rc;
+ }
+
+ EXIT;
+ return copy_to_user((char *)arg, &rec, sizeof(rec))? -EFAULT : 0;
+ }
+
+ case IZO_IOC_REPSTATUS: {
+ __u64 client_kmlsize;
+ struct izo_rcvd_rec *lr_client;
+ struct izo_rcvd_rec rec;
+ struct presto_file_set *fset;
+ int minor;
+ int rc;
+
+ fset = presto_fset(file->f_dentry);
+ if (fset == NULL) {
+ EXIT;
+ return -ENODEV;
+ }
+ minor = presto_f2m(fset);
+
+ client_kmlsize = data->ioc_kmlsize;
+ lr_client = (struct izo_rcvd_rec *) data->ioc_pbuf1;
+
+ rc = izo_repstatus(fset, client_kmlsize,
+ lr_client, &rec);
+ if (rc < 0) {
+ EXIT;
+ return rc;
+ }
+
+ EXIT;
+ return copy_to_user((char *)arg, &rec, sizeof(rec))? -EFAULT : 0;
+ }
+
+ case IZO_IOC_GET_CHANNEL: {
+ struct presto_file_set *fset;
+
+ fset = presto_fset(file->f_dentry);
+ if (fset == NULL) {
+ EXIT;
+ return -ENODEV;
+ }
+
+ data->ioc_dev = fset->fset_cache->cache_psdev->uc_minor;
+ CDEBUG(D_PSDEV, "CHANNEL %d\n", data->ioc_dev);
+ EXIT;
+ return copy_to_user((char *)arg, data, sizeof(*data))? -EFAULT : 0;
+ }
+
+ case IZO_IOC_SET_IOCTL_UID:
+ izo_authorized_uid = data->ioc_uid;
+ EXIT;
+ return 0;
+
+ case IZO_IOC_SET_PID:
+ rc = izo_psdev_setpid(data->ioc_dev);
+ EXIT;
+ return rc;
+
+ case IZO_IOC_SET_CHANNEL:
+ rc = izo_psdev_setchannel(file, data->ioc_dev);
+ EXIT;
+ return rc;
+
+ case IZO_IOC_GET_KML_SIZE: {
+ struct presto_file_set *fset;
+ __u64 kmlsize;
+
+ fset = presto_fset(file->f_dentry);
+ if (fset == NULL) {
+ EXIT;
+ return -ENODEV;
+ }
+
+ kmlsize = presto_kml_offset(fset) + fset->fset_kml_logical_off;
+
+ EXIT;
+ return copy_to_user((char *)arg, &kmlsize, sizeof(kmlsize))?-EFAULT : 0;
+ }
+
+ case IZO_IOC_PURGE_FILE_DATA: {
+ struct presto_file_set *fset;
+
+ fset = presto_fset(file->f_dentry);
+ if (fset == NULL) {
+ EXIT;
+ return -ENODEV;
+ }
+
+ rc = izo_purge_file(fset, data->ioc_inlbuf1);
+ EXIT;
+ return rc;
+ }
+
+ case IZO_IOC_GET_FILEID: {
+ rc = izo_get_fileid(file, data);
+ EXIT;
+ if (rc)
+ return rc;
+ return copy_to_user((char *)arg, data, sizeof(*data))? -EFAULT : 0;
+ }
+
+ case IZO_IOC_SET_FILEID: {
+ rc = izo_set_fileid(file, data);
+ EXIT;
+ if (rc)
+ return rc;
+ return copy_to_user((char *)arg, data, sizeof(*data))? -EFAULT : 0;
+ }
+
+ case IZO_IOC_ADJUST_LML: {
+ struct lento_vfs_context *info;
+ info = (struct lento_vfs_context *)data->ioc_inlbuf1;
+ rc = presto_adjust_lml(file, info);
+ EXIT;
+ return rc;
+ }
+
+ case IZO_IOC_CONNECT: {
+ struct presto_file_set *fset;
+ int minor;
+
+ fset = presto_fset(file->f_dentry);
+ if (fset == NULL) {
+ EXIT;
+ return -ENODEV;
+ }
+ minor = presto_f2m(fset);
+
+ rc = izo_upc_connect(minor, data->ioc_ino,
+ data->ioc_generation, data->ioc_uuid,
+ data->ioc_flags);
+ EXIT;
+ return rc;
+ }
+
+ case IZO_IOC_GO_FETCH_KML: {
+ struct presto_file_set *fset;
+ int minor;
+
+ fset = presto_fset(file->f_dentry);
+ if (fset == NULL) {
+ EXIT;
+ return -ENODEV;
+ }
+ minor = presto_f2m(fset);
+
+ rc = izo_upc_go_fetch_kml(minor, fset->fset_name,
+ data->ioc_uuid, data->ioc_kmlsize);
+ EXIT;
+ return rc;
+ }
+
+ case IZO_IOC_REVOKE_PERMIT:
+ if (data->ioc_flags)
+ rc = izo_revoke_permit(file->f_dentry, data->ioc_uuid);
+ else
+ rc = izo_revoke_permit(file->f_dentry, NULL);
+ EXIT;
+ return rc;
+
+ case IZO_IOC_CLEAR_FSET:
+ rc = izo_clear_fsetroot(file->f_dentry);
+ EXIT;
+ return rc;
+
+ case IZO_IOC_CLEAR_ALL_FSETS: {
+ struct presto_file_set *fset;
+
+ fset = presto_fset(file->f_dentry);
+ if (fset == NULL) {
+ EXIT;
+ return -ENODEV;
+ }
+
+ rc = izo_clear_all_fsetroots(fset->fset_cache);
+ EXIT;
+ return rc;
+ }
+
+ case IZO_IOC_SET_FSET:
+ /*
+ * Mark this dentry as being a fileset root.
+ */
+ rc = presto_set_fsetroot_from_ioc(file->f_dentry,
+ data->ioc_inlbuf1,
+ data->ioc_flags);
+ EXIT;
+ return rc;
+
+
+ case IZO_IOC_MARK: {
+ int res = 0; /* resulting flags - returned to user */
+ int error;
+
+ CDEBUG(D_DOWNCALL, "mark inode: %ld, and: %x, or: %x, what %d\n",
+ file->f_dentry->d_inode->i_ino, data->ioc_and_flag,
+ data->ioc_or_flag, data->ioc_mark_what);
+
+ switch (data->ioc_mark_what) {
+ case MARK_DENTRY:
+ error = izo_mark_dentry(file->f_dentry,
+ data->ioc_and_flag,
+ data->ioc_or_flag, &res);
+ break;
+ case MARK_FSET:
+ error = izo_mark_fset(file->f_dentry,
+ data->ioc_and_flag,
+ data->ioc_or_flag, &res);
+ break;
+ case MARK_CACHE:
+ error = izo_mark_cache(file->f_dentry,
+ data->ioc_and_flag,
+ data->ioc_or_flag, &res);
+ break;
+ case MARK_GETFL: {
+ int fflags, cflags;
+ data->ioc_and_flag = 0xffffffff;
+ data->ioc_or_flag = 0;
+ error = izo_mark_dentry(file->f_dentry,
+ data->ioc_and_flag,
+ data->ioc_or_flag, &res);
+ if (error)
+ break;
+ error = izo_mark_fset(file->f_dentry,
+ data->ioc_and_flag,
+ data->ioc_or_flag, &fflags);
+ if (error)
+ break;
+ error = izo_mark_cache(file->f_dentry,
+ data->ioc_and_flag,
+ data->ioc_or_flag,
+ &cflags);
+
+ if (error)
+ break;
+ data->ioc_and_flag = fflags;
+ data->ioc_or_flag = cflags;
+ break;
+ }
+ default:
+ error = -EINVAL;
+ }
+
+ if (error) {
+ EXIT;
+ return error;
+ }
+ data->ioc_mark_what = res;
+ CDEBUG(D_DOWNCALL, "mark inode: %ld, and: %x, or: %x, what %x\n",
+ file->f_dentry->d_inode->i_ino, data->ioc_and_flag,
+ data->ioc_or_flag, data->ioc_mark_what);
+
+ EXIT;
+ return copy_to_user((char *)arg, data, sizeof(*data))? -EFAULT : 0;
+ }
+#if 0
+ case IZO_IOC_CLIENT_MAKE_BRANCH: {
+ struct presto_file_set *fset;
+ int minor;
+
+ fset = presto_fset(file->f_dentry);
+ if (fset == NULL) {
+ EXIT;
+ return -ENODEV;
+ }
+ minor = presto_f2m(fset);
+
+ rc = izo_upc_client_make_branch(minor, fset->fset_name,
+ data->ioc_inlbuf1,
+ data->ioc_inlbuf2);
+ EXIT;
+ return rc;
+ }
+#endif
+ case IZO_IOC_SERVER_MAKE_BRANCH: {
+ struct presto_file_set *fset;
+ int minor;
+
+ fset = presto_fset(file->f_dentry);
+ if (fset == NULL) {
+ EXIT;
+ return -ENODEV;
+ }
+ minor = presto_f2m(fset);
+
+ izo_upc_server_make_branch(minor, data->ioc_inlbuf1);
+ EXIT;
+ return 0;
+ }
+ case IZO_IOC_SET_KMLSIZE: {
+ struct presto_file_set *fset;
+ int minor;
+ struct izo_rcvd_rec rec;
+
+ fset = presto_fset(file->f_dentry);
+ if (fset == NULL) {
+ EXIT;
+ return -ENODEV;
+ }
+ minor = presto_f2m(fset);
+
+ rc = izo_upc_set_kmlsize(minor, fset->fset_name, data->ioc_uuid,
+ data->ioc_kmlsize);
+
+ if (rc != 0) {
+ EXIT;
+ return rc;
+ }
+
+ rc = izo_rcvd_get(&rec, fset, data->ioc_uuid);
+ if (rc == -EINVAL) {
+ /* We don't know anything about this uuid yet; no
+ * worries. */
+ memset(&rec, 0, sizeof(rec));
+ } else if (rc <= 0) {
+ CERROR("InterMezzo: error reading last_rcvd: %d\n", rc);
+ EXIT;
+ return rc;
+ }
+ rec.lr_remote_offset = data->ioc_kmlsize;
+ rc = izo_rcvd_write(fset, &rec);
+ if (rc <= 0) {
+ CERROR("InterMezzo: error writing last_rcvd: %d\n", rc);
+ EXIT;
+ return rc;
+ }
+ EXIT;
+ return rc;
+ }
+ case IZO_IOC_BRANCH_UNDO: {
+ struct presto_file_set *fset;
+ int minor;
- if ( ISLENTO(minor) )
- goto cache;
+ fset = presto_fset(file->f_dentry);
+ if (fset == NULL) {
+ EXIT;
+ return -ENODEV;
+ }
+ minor = presto_f2m(fset);
- if ( !presto_chk(de, PRESTO_DATA) ) {
- CDEBUG(D_CACHE, "doing lento_opendir\n");
- rc = presto_opendir_upcall(minor, file->f_dentry, fset->fset_mtpt, SYNCHRONOUS);
+ rc = izo_upc_branch_undo(minor, fset->fset_name,
+ data->ioc_inlbuf1);
+ EXIT;
+ return rc;
}
+ case IZO_IOC_BRANCH_REDO: {
+ struct presto_file_set *fset;
+ int minor;
+
+ fset = presto_fset(file->f_dentry);
+ if (fset == NULL) {
+ EXIT;
+ return -ENODEV;
+ }
+ minor = presto_f2m(fset);
- if ( rc ) {
- printk("presto_dir_open: DATA_OK: %d, ino: %ld, error %d\n",
- presto_chk(de, PRESTO_DATA), inode->i_ino, rc);
- return rc ;
+ rc = izo_upc_branch_redo(minor, fset->fset_name,
+ data->ioc_inlbuf1);
+ EXIT;
+ return rc;
}
- cache:
- fops = filter_c2cdfops(cache->cache_filter);
- if ( fops->open ) {
- rc = fops->open(inode, file);
+ case TCGETS:
+ EXIT;
+ return -EINVAL;
+
+ default:
+ EXIT;
+ return -EINVAL;
+
}
- presto_set(de, PRESTO_DATA | PRESTO_ATTR);
- CDEBUG(D_CACHE, "returns %d, data %d, attr %d\n", rc,
- presto_chk(de, PRESTO_DATA), presto_chk(de, PRESTO_ATTR));
+ EXIT;
return 0;
}
struct file_operations presto_dir_fops = {
- open: presto_dir_open
+ .ioctl = presto_ioctl
};
struct inode_operations presto_dir_iops = {
- create: presto_create,
- lookup: presto_lookup,
- link: presto_link,
- unlink: presto_unlink,
- symlink: presto_symlink,
- mkdir: presto_mkdir,
- rmdir: presto_rmdir,
- mknod: presto_mknod,
- rename: presto_rename,
- permission: presto_permission,
- setattr: presto_setattr,
+ .create = presto_create,
+ .lookup = presto_lookup,
+ .link = presto_link,
+ .unlink = presto_unlink,
+ .symlink = presto_symlink,
+ .mkdir = presto_mkdir,
+ .rmdir = presto_rmdir,
+ .mknod = presto_mknod,
+ .rename = presto_rename,
+ .permission = presto_permission,
+ .setattr = presto_setattr,
#ifdef CONFIG_FS_EXT_ATTR
- set_ext_attr: presto_set_ext_attr,
+ .set_ext_attr = presto_set_ext_attr,
#endif
-
};
+
+
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)