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

Next file: linux/fs/coda/inode.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.131/linux/fs/coda/dir.c linux/fs/coda/dir.c
@@ -45,16 +45,15 @@
 /* dentry ops */
 static int coda_dentry_revalidate(struct dentry *de);
 static void coda_dentry_delete(struct dentry *);
+
 /* support routines */
 static int coda_venus_readdir(struct file *filp, void *dirent, 
 			      filldir_t filldir);
 int coda_fsync(struct file *, struct dentry *dentry);
-static int coda_refresh_inode(struct dentry *dentry);
 
 int coda_crossvol_rename = 0;
 int coda_hasmknod = 0;
 
-
 struct dentry_operations coda_dentry_operations =
 {
 	coda_dentry_revalidate, /* revalidate */
@@ -119,24 +118,24 @@
 	size_t length = entry->d_name.len;
 	
         ENTRY;
-        CDEBUG(D_INODE, "name %s, len %d in ino %ld\n", 
-	       name, length, dir->i_ino);
-
-	if (!dir || !S_ISDIR(dir->i_mode)) {
-		printk("coda_lookup: inode is NULL or not a directory\n");
-		return -ENOTDIR;
-	}
 
 	dircnp = ITOC(dir);
 
-	if ( length > CFS_MAXNAMLEN ) {
+	if ( length > CODA_MAXNAMLEN ) {
 	        printk("name too long: lookup, %s (%*s)\n", 
 		       coda_f2s(&dircnp->c_fid), length, name);
 		return -ENAMETOOLONG;
 	}
-	
-	CDEBUG(D_INODE, "lookup: %*s in %s\n", length, name, 
-	       coda_f2s(&dircnp->c_fid));
+
+
+	if (!dir || !S_ISDIR(dir->i_mode)) {
+		printk("coda_lookup: inode is NULL or not a directory\n");
+		return -ENOTDIR;
+	}
+
+
+        CDEBUG(D_INODE, "name %s, len %d in ino %ld, fid %s\n", 
+	       name, length, dir->i_ino, coda_f2s(&dircnp->c_fid));
 
         /* control object, create inode on the fly */
         if (coda_isroot(dir) && coda_iscontrol(name, length)) {
@@ -152,8 +151,8 @@
 
 	res_inode = NULL;
 	if (!error) {
-		if (type & CFS_NOCACHE) {
-			type &= (~CFS_NOCACHE);
+		if (type & CODA_NOCACHE) {
+			type &= (~CODA_NOCACHE);
 			CDEBUG(D_INODE, "dropme set for %s\n", 
 			       coda_f2s(&resfid));
 			dropme = 1;
@@ -184,7 +183,7 @@
 
 int coda_permission(struct inode *inode, int mask)
 {
-        struct coda_inode_info *cp;
+        struct coda_inode_info *cp = ITOC(inode);
         int error;
  
         ENTRY;
@@ -192,7 +191,6 @@
 	coda_permission_stat.count++;
 
         if ( mask == 0 ) {
-                EXIT;
                 return 0;
         }
 
@@ -204,7 +202,6 @@
 	}
 
         cp = ITOC(inode);
-        CHECK_CNODE(cp);
 
         CDEBUG(D_INODE, "mask is %o\n", mask);
         error = venus_access(inode->i_sb, &(cp->c_fid), mask);
@@ -247,9 +244,8 @@
 		return -EPERM;
 
 	dircnp = ITOC(dir);
-        CHECK_CNODE(dircnp);
 
-        if ( length > CFS_MAXNAMLEN ) {
+        if ( length > CODA_MAXNAMLEN ) {
 		printk("name too long: create, %s(%s)\n", 
 		       coda_f2s(&dircnp->c_fid), name);
 		return -ENAMETOOLONG;
@@ -304,9 +300,8 @@
 		return -EPERM;
 
 	dircnp = ITOC(dir);
-        CHECK_CNODE(dircnp);
 
-        if ( length > CFS_MAXNAMLEN ) {
+        if ( length > CODA_MAXNAMLEN ) {
 		printk("name too long: mknod, %s(%s)\n", 
 		       coda_f2s(&dircnp->c_fid), name);
 		return -ENAMETOOLONG;
@@ -353,14 +348,13 @@
 		return -ENOENT;
 	}
 
-        if ( len > CFS_MAXNAMLEN )
+        if ( len > CODA_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)), mode);
@@ -410,12 +404,11 @@
 
         dir_cnp = ITOC(dir_inode);
         cnp = ITOC(inode);
-        CHECK_CNODE(cnp);
 
 	CDEBUG(D_INODE, "old: fid: %s\n", coda_f2s(&(cnp->c_fid)));
 	CDEBUG(D_INODE, "directory: %s\n", coda_f2s(&(dir_cnp->c_fid)));
 
-        if ( len > CFS_MAXNAMLEN ) {
+        if ( len > CODA_MAXNAMLEN ) {
                 printk("coda_link: name too long. \n");
                 return -ENAMETOOLONG;
         }
@@ -428,8 +421,9 @@
 		++inode->i_count;
 		d_instantiate(de, inode);
 		inode->i_nlink++;
-	} else {
+	} else  {
 		d_drop(de);
+		return error;
 	}
 
         CDEBUG(D_INODE, "link result %d\n",error);
@@ -453,11 +447,11 @@
 	if (coda_isroot(dir_inode) && coda_iscontrol(name, len))
 		return -EPERM;
 
-	if ( len > CFS_MAXNAMLEN )
+	if ( len > CODA_MAXNAMLEN )
                 return -ENAMETOOLONG;
 
 	symlen = strlen(symname);
-	if ( symlen > CFS_MAXPATHLEN )
+	if ( symlen > CODA_MAXPATHLEN )
                 return -ENAMETOOLONG;
 
         CDEBUG(D_INODE, "symname: %s, length: %d\n", symname, symlen);
@@ -467,10 +461,10 @@
 	 * an inode for the entry we have to drop it. 
 	 */
 	d_drop(de);
-
 	error = venus_symlink(dir_inode->i_sb, &(dir_cnp->c_fid), name, len, 
 			      symname, symlen);
 
+	/* mtime is no good anymore */
 	if ( !error ) {
 		dir_cnp->c_flags |= C_VATTR;
 	}
@@ -483,7 +477,7 @@
 /* destruction routines: unlink, rmdir */
 int coda_unlink(struct inode *dir, struct dentry *de)
 {
-        struct coda_inode_info *dircnp;
+        struct coda_inode_info *dircnp = ITOC(dir);
         int error;
 	const char *name = de->d_name.name;
 	int len = de->d_name.len;
@@ -491,25 +485,18 @@
 	ENTRY;
 	coda_vfs_stat.unlink++;
 
-        dircnp = ITOC(dir);
-        CHECK_CNODE(dircnp);
-
-        CDEBUG(D_INODE, " %s in %s, ino %ld\n", name , 
+        CDEBUG(D_INODE, " %s in %s, dirino %ld\n", name , 
 	       coda_f2s(&(dircnp->c_fid)), dir->i_ino);
 
-        /* this file should no longer be in the namecache! */
-
         error = venus_remove(dir->i_sb, &(dircnp->c_fid), name, len);
-
         if ( error ) {
                 CDEBUG(D_INODE, "upc returned error %d\n", error);
                 return error;
         }
 
-        /* cache management */
+        /* cache management: mtime has changed, ask Venus */
 	dircnp->c_flags |= C_VATTR;
 	de->d_inode->i_nlink--;
-
 	d_delete(de);
 
         return 0;
@@ -530,19 +517,12 @@
 		return -ENOENT;
 	}
         dircnp = ITOC(dir);
-        CHECK_CNODE(dircnp);
 
-	if (len > CFS_MAXNAMLEN)
+	if (len > CODA_MAXNAMLEN)
 		return -ENAMETOOLONG;
 
 	if (!list_empty(&de->d_hash))
 		return -EBUSY;
-
-	/* update i_nlink and free the inode before unlinking;
-	   if rmdir fails a new lookup set i_nlink right.*/
-	if (de->d_inode->i_nlink)
-		de->d_inode->i_nlink --;
-
 	error = venus_rmdir(dir->i_sb, &(dircnp->c_fid), name, len);
 
         if ( error ) {
@@ -550,6 +530,9 @@
                 return error;
         }
 
+	if (de->d_inode->i_nlink)
+		de->d_inode->i_nlink --;
+
         return 0;
 }
 
@@ -569,7 +552,7 @@
 	ENTRY;
 	coda_vfs_stat.rename++;
 
-        if ( (old_length > CFS_MAXNAMLEN) || new_length > CFS_MAXNAMLEN ) {
+        if ( (old_length > CODA_MAXNAMLEN) || new_length > CODA_MAXNAMLEN ) {
                 return -ENAMETOOLONG;
         }
 
@@ -641,8 +624,6 @@
         }
 
         cnp = ITOC(inode);
-        CHECK_CNODE(cnp);
-        
         if ( !cnp->c_ovp ) {
                 CDEBUG(D_FILE, "open inode pointer = NULL.\n");
                 return -EIO;
@@ -658,8 +639,8 @@
                 result = open_file.f_op->readdir(&open_file, dirent, filldir);
         }
 	coda_restore_codafile(inode, file, cnp->c_ovp, &open_file);
-	return result;
         EXIT;
+	return result;
 }
 
 /* ask venus to cache the file and return the inode of the container file,
@@ -673,15 +654,17 @@
         struct inode *cont_inode = NULL;
         unsigned short flags = f->f_flags & (~O_EXCL);
 	unsigned short coda_flags = coda_flags_to_cflags(flags);
+	struct coda_cred *cred;
 
         ENTRY;
 	coda_vfs_stat.open++;
-        
+
         CDEBUG(D_SPECIAL, "OPEN inode number: %ld, count %d, flags %o.\n", 
 	       f->f_dentry->d_inode->i_ino, f->f_dentry->d_count, flags);
 
         cnp = ITOC(i);
 
+
 	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",
@@ -700,6 +683,10 @@
 		return error;
 	}
 
+	CODA_ALLOC(cred, struct coda_cred *, sizeof(*cred));
+	coda_load_creds(cred);
+	f->private_data = cred;
+
         if (  cnp->c_ovp ) {
 		iput(cnp->c_ovp);
 		cnp->c_ovp = NULL;
@@ -722,10 +709,13 @@
         int error;
         unsigned short flags = (f->f_flags) & (~O_EXCL);
 	unsigned short cflags = coda_flags_to_cflags(flags);
+	struct coda_cred *cred;
 
         ENTRY;
 	coda_vfs_stat.release++;
 
+	cred = (struct coda_cred *)f->private_data;
+
         cnp =ITOC(i);
         CHECK_CNODE(cnp);
         CDEBUG(D_FILE,  
@@ -746,7 +736,10 @@
                 --cnp->c_owrite;
         }
 
-	error = venus_release(i->i_sb, &(cnp->c_fid), cflags);
+	error = venus_release(i->i_sb, &(cnp->c_fid), cflags, cred);
+
+	CODA_FREE(cred, sizeof(*cred));
+	f->private_data = NULL;
 
         CDEBUG(D_FILE, "coda_release: result: %d\n", error);
         return error;
@@ -759,96 +752,97 @@
  * beyond the current_dir pointer.
  */
 
-struct getdents_callback {
-	struct linux_dirent * current_dir;
-	struct linux_dirent * previous;
-	int count;
-	int error;
-};
+
+/* should be big enough to hold any single directory entry */
+#define DIR_BUFSIZE 2048
 
 static int coda_venus_readdir(struct file *filp, void *getdent, 
 			      filldir_t filldir)
 {
-        int result = 0,  offset, count, pos, error = 0;
+        int bufsize;
+	int offset = filp->f_pos; /* offset in the directory file */
+	int count = 0;
+	int pos = 0;      /* offset in the block we read */
+	int result = 0; /* either an error or # of entries returned */
 	int errfill;
-        caddr_t buff = NULL;
+        char *buff = NULL;
         struct venus_dirent *vdirent;
-        struct getdents_callback *dents_callback;
-        int string_offset;
-	int size;
-        char debug[255];
+        int string_offset = (int) (&((struct venus_dirent *)(0))->d_name);
+	int i;
 
         ENTRY;        
 
-        /* we also need the ofset of the string in the dirent struct */
-        string_offset = sizeof ( char )* 2  + sizeof(unsigned int) + 
-                        sizeof(unsigned short);
-
-        dents_callback = (struct getdents_callback *) getdent;
-
-        size = count =  dents_callback->count;
-        CODA_ALLOC(buff, void *, size);
-        if ( ! buff ) { 
+        CODA_ALLOC(buff, char *, DIR_BUFSIZE);
+        if ( !buff ) { 
                 printk("coda_venus_readdir: out of memory.\n");
                 return -ENOMEM;
         }
 
         /* we use this routine to read the file into our buffer */
-        result = read_exec(filp->f_dentry, filp->f_pos, buff, count, 1);
-        if ( result < 0) {
+        bufsize = read_exec(filp->f_dentry, filp->f_pos, buff, DIR_BUFSIZE, 1);
+        if ( bufsize < 0) {
                 printk("coda_venus_readdir: cannot read directory %d.\n",
-		       result);
-                error = result;
+		       bufsize);
+                result = bufsize;
                 goto exit;
         }
-        if ( result == 0) {
-                error = result;
+        if ( bufsize == 0) {
+                result = 0;
                 goto exit;
         }
-
+	
         /* Parse and write into user space. Filldir tells us when done! */
-        offset = filp->f_pos;
-        pos = 0;
-        CDEBUG(D_FILE, "offset %d, count %d.\n", offset, count);
+        CDEBUG(D_FILE, "buffsize: %d offset %d, count %d.\n", 
+	       bufsize, offset, count);
 
-        while ( pos + string_offset < result ) {
+	i = 0;
+	result = 0; 
+        while ( pos + string_offset < bufsize && i < 1024) {
                 vdirent = (struct venus_dirent *) (buff + pos);
 
                 /* test if the name is fully in the buffer */
-                if ( pos + string_offset + (int) vdirent->d_namlen >= result ){
+                if ( pos + string_offset + (int) vdirent->d_namlen >= bufsize ){
+			if ( result == 0 )
+				printk("CODA: Invalid directory cfino: %ld\n", 
+				       filp->f_dentry->d_inode->i_ino);
                         break;
                 }
-                
                 /* now we are certain that we can read the entry from buff */
 
-                /* for debugging, get the string out */
-                memcpy(debug, vdirent->d_name, vdirent->d_namlen);
-                *(debug + vdirent->d_namlen) = '\0';
-
                 /* if we don't have a null entry, copy it */
-                if ( vdirent->d_fileno ) {
+                if ( vdirent->d_fileno && vdirent->d_reclen ) {
                         int namlen  = vdirent->d_namlen;
                         off_t offs  = filp->f_pos; 
                         ino_t ino   = vdirent->d_fileno;
                         char *name  = vdirent->d_name;
-                        /* adjust count */
-                        count = dents_callback->count;
 
-			errfill = filldir(dents_callback,  name, namlen, 
+			errfill = filldir(getdent,  name, namlen, 
 					  offs, ino); 
-CDEBUG(D_FILE, "ino %ld, namlen %d, reclen %d, type %d, pos %d, string_offs %d, name %s, offset %d, count %d.\n", vdirent->d_fileno, vdirent->d_namlen, vdirent->d_reclen, vdirent->d_type, pos,  string_offset, debug, (u_int) offs, dents_callback->count);
-
-		      /* errfill means no space for filling in this round */
-                      if ( errfill < 0 ) break;
+CDEBUG(D_FILE, "entry %d: ino %ld, namlen %d, reclen %d, type %d, pos %d, string_offs %d, name %*s, offset %d, result: %d, errfill: %d.\n", i,vdirent->d_fileno, vdirent->d_namlen, vdirent->d_reclen, vdirent->d_type, pos,  string_offset, vdirent->d_namlen, vdirent->d_name, (u_int) offs, result, errfill);
+			/* errfill means no space for filling in this round */
+			if ( errfill < 0 ) {
+				result = 0;
+				break;
+			}
+                        /* adjust count */
+                        result++;
                 }
                 /* next one */
-                filp->f_pos += (unsigned int) vdirent->d_reclen;
+                filp->f_pos += vdirent->d_reclen;
+		if ( filp->f_pos > filp->f_dentry->d_inode->i_size )
+			break; 
+		if ( !vdirent->d_reclen ) {
+			printk("CODA: Invalid directory, cfino: %ld\n", 
+			       filp->f_dentry->d_inode->i_ino);
+			break;
+		}
                 pos += (unsigned int) vdirent->d_reclen;
+		i++;
         } 
 
 exit:
-        CODA_FREE(buff, size);
-        return error;
+        CODA_FREE(buff, DIR_BUFSIZE);
+        return result;
 }
 
 /* called when a cache lookup succeeds */
@@ -865,6 +859,10 @@
 		cii = ITOC(de->d_inode);
 		if (cii->c_flags & C_PURGE) 
 			valid = 0;
+		if (cii->c_flags & C_FLUSH) {
+			coda_flag_inode_children(inode, C_FLUSH);
+			valid = 0;
+		}
 	}
 	return valid ||  coda_isroot(de->d_inode);
 }
@@ -890,64 +888,74 @@
 }
 
 
-static int coda_refresh_inode(struct dentry *dentry)
+
+/*
+ * This is called when we want to check if the inode has
+ * changed on the server.  Coda makes this easy since the
+ * cache manager Venus issues a downcall to the kernel when this 
+ * happens 
+ */
+
+int coda_revalidate_inode(struct dentry *dentry)
 {
 	struct coda_vattr attr;
-	int error;
+	int error = 0;
 	int old_mode;
 	ino_t old_ino;
 	struct inode *inode = dentry->d_inode;
 	struct coda_inode_info *cii = ITOC(inode);
 
 	ENTRY;
-	
-	error = venus_getattr(inode->i_sb, &(cii->c_fid), &attr);
-	if ( error ) { 
-		make_bad_inode(inode);
-		return -EIO;
-	}
+	CDEBUG(D_INODE, "revalidating: %*s/%*s\n", 
+	       dentry->d_name.len, dentry->d_name.name,
+	       dentry->d_parent->d_name.len, dentry->d_parent->d_name.name);
 
-	/* this inode may be lost if:
-            - it's type changed
-            - it's ino changed 
-	*/
-	old_mode = inode->i_mode;
-	old_ino = inode->i_ino;
-	coda_vattr_to_iattr(inode, &attr);
+	if ( cii->c_flags == 0 )
+		return 0;
 
-	if ((inode->i_ino != old_ino) ||
-	    ((old_mode & S_IFMT) != (inode->i_mode & S_IFMT))) {
+	/* Venus closed the device .... */
+	if ( cii->c_flags & C_DYING ) { 
 		make_bad_inode(inode);
-		inode->i_mode = old_mode;
 		return -EIO;
 	}
+
 	
-	cii->c_flags &= ~C_VATTR;
-	return 0;
-}
+	if (cii->c_flags & (C_VATTR | C_PURGE | C_FLUSH)) {
+		error = venus_getattr(inode->i_sb, &(cii->c_fid), &attr);
+		if ( error ) { 
+			make_bad_inode(inode);
+			return -EIO;
+		}
 
+		/* this inode may be lost if:
+		   - it's ino changed 
+		   - type changes must be permitted for repair and
+		   missing mount points.
+		*/
+		old_mode = inode->i_mode;
+		old_ino = inode->i_ino;
+		coda_vattr_to_iattr(inode, &attr);
 
-/*
- * This is called when we want to check if the inode has
- * changed on the server.  Coda makes this easy since the
- * cache manager Venus issues a downcall to the kernel when this 
- * happens 
- */
 
-int coda_revalidate_inode(struct dentry *dentry)
-{
-	int error = 0;
-	struct coda_inode_info *cii = ITOC(dentry->d_inode);
-
-	ENTRY;
-	CDEBUG(D_INODE, "revalidating: %*s/%*s\n", 
-	       dentry->d_name.len, dentry->d_name.name,
-	       dentry->d_parent->d_name.len, dentry->d_parent->d_name.name);
+		if ((old_mode & S_IFMT) != (inode->i_mode & S_IFMT)) {
+			printk("Coda: inode %ld, fid %s changed type!\n",
+			       inode->i_ino, coda_f2s(&(cii->c_fid)));
+		}
 
-	if (cii->c_flags & (C_VATTR | C_PURGE)) {
-		error = coda_refresh_inode(dentry);
+		/* the following can happen when a local fid is replaced 
+		   with a global one, here we lose and declar the inode bad */
+		if (inode->i_ino != old_ino) {
+			make_bad_inode(inode);
+			inode->i_mode = old_mode;
+			return -EIO;
+		}
+		
+		if ( cii->c_flags ) 
+			coda_flag_inode_children(inode, C_FLUSH);
+		
+		cii->c_flags &= ~(C_VATTR | C_PURGE | C_FLUSH);
 	}
 
-	return error;
+	return 0;
 }
 

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