patch-2.1.75 linux/fs/coda/dir.c

Next file: linux/fs/coda/file.c
Previous file: linux/fs/coda/coda_linux.c
Back to the patch index
Back to the overall index

diff -u --recursive --new-file v2.1.74/linux/fs/coda/dir.c linux/fs/coda/dir.c
@@ -1,5 +1,5 @@
 /*
- * Direcotry operations for Coda filesystem
+ * Directory operations for Coda filesystem
  * Original version: (C) 1996 P. Braam and M. Callahan
  * Rewritten for Linux 2.1. (C) 1997 Carnegie Mellon University
  * 
@@ -22,7 +22,7 @@
 #include <linux/coda_linux.h>
 #include <linux/coda_psdev.h>
 #include <linux/coda_cnode.h>
-#include <linux/coda_namecache.h>
+#include <linux/coda_cache.h>
 
 /* dir inode-ops */
 static int coda_create(struct inode *dir, struct dentry *new, int mode);
@@ -43,8 +43,15 @@
 /* support routines */
 static int coda_venus_readdir(struct file *filp, void *dirent, 
 			      filldir_t filldir);
+int coda_fsync(struct file *, struct dentry *dentry);
 
-
+struct dentry_operations coda_dentry_operations =
+{
+	NULL, /* revalidate */
+	NULL, /* hash */
+	NULL,
+	coda_dentry_delete
+};
 
 struct inode_operations coda_dir_inode_operations =
 {
@@ -80,7 +87,10 @@
         NULL,                   /* mmap */
         coda_open,              /* open */
         coda_release,           /* release */
-        NULL,                   /* fsync */
+	coda_fsync,             /* fsync */
+        NULL,                   
+	NULL,
+	NULL
 };
 
 
@@ -88,9 +98,10 @@
 /* acces routines: lookup, readlink, permission */
 static int coda_lookup(struct inode *dir, struct dentry *entry)
 {
-        struct cnode *dircnp, *savedcnp;
+        struct cnode *dircnp;
 	struct inode *res_inode = NULL;
 	struct ViceFid resfid;
+	int dropme = 0; /* to indicate entry should not be cached */
 	int type;
 	int error = 0;
 	const char *name = entry->d_name.name;
@@ -110,78 +121,56 @@
 	CHECK_CNODE(dircnp);
 
 	if ( length > CFS_MAXNAMLEN ) {
-	        printk("name too long: lookup, %s (%s)\n", 
-		       coda_f2s(&dircnp->c_fid, str), name);
+	        printk("name too long: lookup, %s (%*s)\n", 
+		       coda_f2s(&dircnp->c_fid, str), length, name);
 		return -ENAMETOOLONG;
 	}
 	
-	CDEBUG(D_INODE, "lookup: %s in %s\n", name, 
+	CDEBUG(D_INODE, "lookup: %*s in %s\n", length, name, 
 	       coda_f2s(&dircnp->c_fid, str));
 
         /* control object, create inode on the fly */
-        if ( coda_isroot(dir) && (CFS_CONTROLLEN == length) && 
-	     (strncmp(name, CFS_CONTROL, CFS_CONTROLLEN) == 0) ) {
+        if (coda_isroot(dir) && coda_iscontrol(name, length)) {
 	        error = coda_cnode_makectl(&res_inode, dir->i_sb);
 		CDEBUG(D_SPECIAL, 
-		       "Lookup on CTL object; iput of ino %ld, count %d\n", 
+		       "Lookup on CTL object; dir ino %ld, count %d\n", 
 		       dir->i_ino, dir->i_count);
                 goto exit;
         }
 
-        /* do we have it already in name cache */
-	if ( (savedcnp = cfsnc_lookup(dircnp, name, length)) != NULL ) {
-		CHECK_CNODE(savedcnp);
-		res_inode = CTOI(savedcnp);
-		iget(res_inode->i_sb, res_inode->i_ino);
-		CDEBUG(D_INODE, "cache hit for ino: %ld, count: %d!\n",
-		       res_inode->i_ino, res_inode->i_count);
-		goto exit;
-	}
-	CDEBUG(D_INODE, "name not found in cache!\n");
-
-        /* name not cached */
         error = venus_lookup(dir->i_sb, &(dircnp->c_fid), 
-				(const char *)name, length, &type, &resfid);
+			     (const char *)name, length, &type, &resfid);
 
 	res_inode = NULL;
-	if (!error) {
+	if (!error || (error == -CFS_NOCACHE) ) {
+		if (error == -CFS_NOCACHE) 
+			dropme = 1;
 	    	error = coda_cnode_make(&res_inode, &resfid, dir->i_sb);
 		if (error)
-			return -EACCES;
-		/* put the thing in the name cache */
-		savedcnp = ITOC(res_inode);
-		CHECK_CNODE(savedcnp);
-		CDEBUG(D_INODE, "ABOUT to enter into cache.\n");
-		cfsnc_enter(dircnp, name, length, savedcnp);
-		CDEBUG(D_INODE, "entered in cache\n");
+			return -error;
 	} else if (error != -ENOENT) {
-	        CDEBUG(D_INODE, "error for %s(%s)%d\n",
-		       coda_f2s(&dircnp->c_fid, str), name, error);
+	        CDEBUG(D_INODE, "error for %s(%*s)%d\n",
+		       coda_f2s(&dircnp->c_fid, str), length, name, error);
 		return error;
 	}
-	CDEBUG(D_INODE, "lookup: %s is (%s) type %d result %d\n",
-	       name, coda_f2s(&resfid, str), type, error);
-
-	/* at last we have our inode number from Venus, 
-	   now allocate storage for
-	   the cnode and do iget, and fill in the attributes */
-
+	CDEBUG(D_INODE, "lookup: %s is (%s) type %d result %d, dropme %d\n",
+	       name, coda_f2s(&resfid, str), type, error, dropme);
 
 exit:
 	entry->d_time = 0;
-	entry->d_op = NULL;
+	entry->d_op = &coda_dentry_operations;
 	d_add(entry, res_inode);
+	if ( dropme ) 
+		d_drop(entry);
         EXIT;
         return 0;
 }
 
 
-
 int coda_permission(struct inode *inode, int mask)
 {
         struct cnode *cp;
         int error;
-        int mode = inode->i_mode;
 	char str[50];
  
         ENTRY;
@@ -191,16 +180,10 @@
                 return 0;
         }
 
-        /* we should be able to trust what is in the mode
-           although Venus should be told to return the 
-           correct modes to the kernel */
-        if ( coda_access_cache == 1 ) { 
-            if (current->fsuid == inode->i_uid)
-                mode >>= 6;
-        	else if (in_group_p(inode->i_gid))
-                mode >>= 3;
-        	if (((mode & mask & 0007) == mask) )
-                return 0;
+	if ( coda_access_cache == 1 ) {
+		if ( coda_cache_check(inode, mask) ) {
+			return 0; 
+		}
 	}
 
         cp = ITOC(inode);
@@ -212,6 +195,10 @@
         CDEBUG(D_INODE, "fid: %s, ino: %ld (mask: %o) error: %d\n", 
 	       coda_f2s(&(cp->c_fid), str), inode->i_ino, mask, error);
 
+	if ( error == 0 ) {
+		coda_cache_enter(inode, mask);
+	}
+
         return error; 
 }
 
@@ -235,6 +222,10 @@
                 printk("coda_create: inode is null or not a directory\n");
                 return -ENOENT;
         }
+
+	if (coda_isroot(dir) && coda_iscontrol(name, length))
+		return -EPERM;
+
 	dircnp = ITOC(dir);
         CHECK_CNODE(dircnp);
 
@@ -263,7 +254,7 @@
 
 	/* invalidate the directory cnode's attributes */
 	dircnp->c_flags &= ~C_VATTR;
-	cfsnc_zapfid(&(dircnp->c_fid));
+/* 	cfsnc_zapfid(&(dircnp->c_fid)); */
 
 	d_instantiate(de, result);
         return 0;
@@ -280,15 +271,18 @@
 	struct ViceFid newfid;
 	char fidstr[50];
 
+
 	if (!dir || !S_ISDIR(dir->i_mode)) {
 		printk("coda_mkdir: inode is NULL or not a directory\n");
 		return -ENOENT;
 	}
-        dircnp = ITOC(dir);
-        CHECK_CNODE(dircnp);
-
         if ( len > CFS_MAXNAMLEN )
                 return -ENAMETOOLONG;
+	if (coda_isroot(dir) && coda_iscontrol(name, len))
+		return -EPERM;
+
+        dircnp = ITOC(dir);
+        CHECK_CNODE(dircnp);
 
 	CDEBUG(D_INODE, "mkdir %s (len %d) in %s, mode %o.\n", 
 	       name, len, coda_f2s(&(dircnp->c_fid), fidstr), mode);
@@ -312,7 +306,7 @@
 	
 	/* invalidate the directory cnode's attributes */
 	dircnp->c_flags &= ~C_VATTR;
-	cfsnc_zapfid(&(dircnp->c_fid));
+/* 	cfsnc_zapfid(&(dircnp->c_fid)); */
 
 	dir->i_nlink++;
 	d_instantiate(de, inode);
@@ -330,6 +324,9 @@
 
         ENTRY;
 
+	if (coda_isroot(dir_inode) && coda_iscontrol(name, len))
+		return -EPERM;
+
         dir_cnp = ITOC(dir_inode);
         CHECK_CNODE(dir_cnp);
         cnp = ITOC(inode);
@@ -350,8 +347,8 @@
 
 	if (  ! error ) { 
 	      dir_cnp->c_flags &= ~C_VATTR;
-	      cfsnc_zapfid(&(dir_cnp->c_fid));
-	      cfsnc_zapfid(&(cnp->c_fid));
+/* 	      cfsnc_zapfid(&(dir_cnp->c_fid)); */
+/* 	      cfsnc_zapfid(&(cnp->c_fid)); */
 
 	      inode->i_nlink++;
 	      d_instantiate(de, inode);
@@ -362,9 +359,8 @@
 }
 
 
-static int 
-coda_symlink(struct inode *dir_inode, struct dentry *de,
-             const char *symname)
+static int coda_symlink(struct inode *dir_inode, struct dentry *de,
+			const char *symname)
 {
         const char *name = de->d_name.name;
 	int len = de->d_name.len;
@@ -374,23 +370,23 @@
         
         ENTRY;
 
-	error = -ENAMETOOLONG;
-	if ( len > CFS_MAXNAMLEN ) { 
-	        return error;
-	}
+	if (coda_isroot(dir_inode) && coda_iscontrol(name, len))
+		return -EPERM;
+
+	if ( len > CFS_MAXNAMLEN )
+                return -ENAMETOOLONG;
 
 	symlen = strlen(symname);
-	if ( symlen > CFS_MAXNAMLEN ) { 
-	        return error;
-	}
+	if ( symlen > CFS_MAXPATHLEN )
+                return -ENAMETOOLONG;
+
         CDEBUG(D_INODE, "symname: %s, length: %d\n", symname, symlen);
 
 	error = venus_symlink(dir_inode->i_sb, &(dir_cnp->c_fid), name, len, 
 			      symname, symlen);
 
-	if ( !error ) {
-	  d_drop(de);
-	}
+	if ( !error )
+		d_drop(de);
 
         CDEBUG(D_INODE, "in symlink result %d\n",error);
         EXIT;
@@ -416,7 +412,7 @@
 	       coda_f2s(&(dircnp->c_fid), fidstr), dir->i_ino);
 
         /* this file should no longer be in the namecache! */
-        cfsnc_zapfile(dircnp, (const char *)name, len);
+/*         cfsnc_zapfile(dircnp, (const char *)name, len); */
 
         error = venus_remove(dir->i_sb, &(dircnp->c_fid), name, len);
 
@@ -427,7 +423,7 @@
 
         /* cache management */
 	dircnp->c_flags &= ~C_VATTR;
-	cfsnc_zapfid(&(dircnp->c_fid));
+/* 	cfsnc_zapfid(&(dircnp->c_fid)); */
 	
 	de->d_inode->i_nlink--;
 	d_delete(de);
@@ -452,8 +448,15 @@
 	if (len > CFS_MAXNAMLEN)
 		return -ENAMETOOLONG;
 
-        /* this directory name should no longer be in the namecache */
-        cfsnc_zapfile(dircnp, (const char *)name, len);
+	error = -EBUSY;
+	if (de->d_count > 1) {
+		/* Attempt to shrink child dentries ... */
+		shrink_dcache_parent(de);
+		if (de->d_count > 1)
+			return error;
+	}
+	/* Drop the dentry to force a new lookup */
+	d_drop(de);
 
 	error = venus_rmdir(dir->i_sb, &(dircnp->c_fid), name, len);
 
@@ -462,9 +465,6 @@
                 return error;
         }
 
-	dircnp->c_flags &= ~C_VATTR;
-	cfsnc_zapfid(&(dircnp->c_fid));
-
 	dir->i_nlink--;
 	d_delete(de);
 
@@ -496,8 +496,8 @@
         }
 
         /* the old file should go from the namecache */
-        cfsnc_zapfile(old_cnp, (const char *)old_name, old_length);
-        cfsnc_zapfile(new_cnp, (const char *)new_name, new_length);
+/*         cfsnc_zapfile(old_cnp, (const char *)old_name, old_length); */
+/*         cfsnc_zapfile(new_cnp, (const char *)new_name, new_length); */
 
         /* cross directory moves */
 	if (new_dir != old_dir  &&
@@ -585,19 +585,17 @@
         int error = 0;
         struct inode *cont_inode = NULL;
         unsigned short flags = f->f_flags;
+	unsigned short coda_flags = coda_flags_to_cflags(flags);
 
         ENTRY;
         
         CDEBUG(D_SPECIAL, "OPEN inode number: %ld, flags %o.\n", 
 	       f->f_dentry->d_inode->i_ino, flags);
 
-        if ( flags & O_CREAT ) {
-                flags &= ~O_EXCL; /* taken care of by coda_create ?? */
-        }
         cnp = ITOC(i);
         CHECK_CNODE(cnp);
 
-	error = venus_open(i->i_sb, &(cnp->c_fid), flags, &ino, &dev); 
+	error = venus_open(i->i_sb, &(cnp->c_fid), coda_flags, &ino, &dev); 
 	if (error) {
 	        CDEBUG(D_FILE, "venus: dev %d, inode %ld, out->result %d\n",
 		       dev, ino, error);
@@ -618,14 +616,13 @@
                 CDEBUG(D_FILE, "GRAB: coda_inode_grab: ino %ld, ops at %x\n", 
 		       cont_inode->i_ino, (int)cont_inode->i_op);
                 cnp->c_ovp = cont_inode; 
-		cnp->c_odentry.d_inode = cont_inode;
         } 
         cnp->c_ocount++;
 
         /* if opened for writing flush cache entry.  */
-        if ( flags & (O_WRONLY | O_RDWR) ) {
-	        cfsnc_zapfid(&(cnp->c_fid));
-	} 
+/*         if ( flags & (O_WRONLY | O_RDWR) ) { */
+/* 	        cfsnc_zapfid(&(cnp->c_fid)); */
+/* 	}  */
 
         CDEBUG(D_FILE, "result %d, coda i->i_count is %d for ino %ld\n", 
 	       error, i->i_count, i->i_ino);
@@ -641,6 +638,7 @@
         struct cnode *cnp;
         int error;
         unsigned short flags = f->f_flags;
+	unsigned short cflags = coda_flags_to_cflags(flags);
 
         ENTRY;
 
@@ -664,7 +662,7 @@
                 --cnp->c_owrite;
         }
 
-	error = venus_release(i->i_sb, &(cnp->c_fid), flags);
+	error = venus_release(i->i_sb, &(cnp->c_fid), cflags);
 
         CDEBUG(D_FILE, "coda_release: result: %d\n", error);
         return error;
@@ -693,6 +691,7 @@
         struct venus_dirent *vdirent;
         struct getdents_callback *dents_callback;
         int string_offset;
+	int size;
         char debug[255];
 
         ENTRY;        
@@ -703,8 +702,8 @@
 
         dents_callback = (struct getdents_callback *) getdent;
 
-        count =  dents_callback->count;
-        CODA_ALLOC(buff, void *, count);
+        size = count =  dents_callback->count;
+        CODA_ALLOC(buff, void *, size);
         if ( ! buff ) { 
                 printk("coda_venus_readdir: out of memory.\n");
                 return -ENOMEM;
@@ -764,6 +763,6 @@
         } 
 
 exit:
-        CODA_FREE(buff, count);
+        CODA_FREE(buff, size);
         return error;
 }

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov