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
- Lines: 603
- Date:
Fri Dec 18 12:45:00 1998
- Orig file:
v2.1.131/linux/fs/coda/dir.c
- Orig date:
Wed Dec 16 10:32:55 1998
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