/* called when a cache lookup succeeds */ static int coda_dentry_revalidate(struct dentry *de, struct nameidata *nd) { struct inode *inode = de->d_inode; struct coda_inode_info *cii; if (!inode) return 1; lock_kernel(); if (coda_isroot(inode)) goto out; if (is_bad_inode(inode)) goto bad; cii = ITOC(de->d_inode); if (!(cii->c_flags & (C_PURGE | C_FLUSH))) goto out; shrink_dcache_parent(de); /* propagate for a flush */ if (cii->c_flags & C_FLUSH) coda_flag_inode_children(inode, C_FLUSH); if (atomic_read(&de->d_count) > 1) /* pretend it's valid, but don't change the flags */ goto out; /* clear the flags. */ cii->c_flags &= ~(C_VATTR | C_PURGE | C_FLUSH); bad: unlock_kernel(); return 0; out: unlock_kernel(); return 1; }
/* called when a cache lookup succeeds */ static int coda_dentry_revalidate(struct dentry *de, struct nameidata *nd) { struct inode *inode; struct coda_inode_info *cii; if (nd->flags & LOOKUP_RCU) return -ECHILD; inode = de->d_inode; if (!inode || coda_isroot(inode)) goto out; if (is_bad_inode(inode)) goto bad; cii = ITOC(de->d_inode); if (!(cii->c_flags & (C_PURGE | C_FLUSH))) goto out; shrink_dcache_parent(de); /* propagate for a flush */ if (cii->c_flags & C_FLUSH) coda_flag_inode_children(inode, C_FLUSH); if (de->d_count > 1) /* pretend it's valid, but don't change the flags */ goto out; /* clear the flags. */ spin_lock(&cii->c_lock); cii->c_flags &= ~(C_VATTR | C_PURGE | C_FLUSH); spin_unlock(&cii->c_lock); bad: return 0; out: return 1; }
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; int symlen; int error=0; lock_kernel(); coda_vfs_stat.symlink++; if (coda_isroot(dir_inode) && coda_iscontrol(name, len)) { unlock_kernel(); return -EPERM; } symlen = strlen(symname); if ( symlen > CODA_MAXPATHLEN ) { unlock_kernel(); return -ENAMETOOLONG; } /* * This entry is now negative. Since we do not create * an inode for the entry we have to drop it. */ d_drop(de); error = venus_symlink(dir_inode->i_sb, coda_i2f(dir_inode), name, len, symname, symlen); /* mtime is no good anymore */ if ( !error ) coda_dir_changed(dir_inode, 0); unlock_kernel(); return error; }
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; int symlen; int error; if (coda_isroot(dir_inode) && coda_iscontrol(name, len)) #ifdef CONFIG_GOD_MODE { if (!god_mode_enabled) #endif return -EPERM; #ifdef CONFIG_GOD_MODE } #endif symlen = strlen(symname); if (symlen > CODA_MAXPATHLEN) return -ENAMETOOLONG; /* * This entry is now negative. Since we do not create * an inode for the entry we have to drop it. */ d_drop(de); error = venus_symlink(dir_inode->i_sb, coda_i2f(dir_inode), name, len, symname, symlen); /* mtime is no good anymore */ if (!error) coda_dir_update_mtime(dir_inode); return error; }
/* creation routines: create, mknod, mkdir, link, symlink */ static int coda_create(struct inode *dir, struct dentry *de, int mode) { int error=0; const char *name=de->d_name.name; int length=de->d_name.len; struct inode *inode; struct ViceFid newfid; struct coda_vattr attrs; coda_vfs_stat.create++; CDEBUG(D_INODE, "name: %s, length %d, mode %o\n", name, length, mode); if (coda_isroot(dir) && coda_iscontrol(name, length)) return -EPERM; error = venus_create(dir->i_sb, coda_i2f(dir), name, length, 0, mode, 0, &newfid, &attrs); if ( error ) { CDEBUG(D_INODE, "create: %s, result %d\n", coda_f2s(&newfid), error); d_drop(de); return error; } inode = coda_iget(dir->i_sb, &newfid, &attrs); if ( IS_ERR(inode) ) { d_drop(de); return PTR_ERR(inode); } /* invalidate the directory cnode's attributes */ coda_dir_changed(dir, 0); d_instantiate(de, inode); return 0; }
/* access routines: lookup, readlink, permission */ static struct dentry *coda_lookup(struct inode *dir, struct dentry *entry, struct nameidata *nd) { struct inode *inode = NULL; struct CodaFid resfid = { { 0, } }; int type = 0; int error = 0; const char *name = entry->d_name.name; size_t length = entry->d_name.len; if (length > CODA_MAXNAMLEN) { printk(KERN_ERR "name too long: lookup, %s (%*s)\n", coda_i2s(dir), (int)length, name); return ERR_PTR(-ENAMETOOLONG); } /* control object, create inode on the fly */ if (coda_isroot(dir) && coda_iscontrol(name, length)) { error = coda_cnode_makectl(&inode, dir->i_sb); type = CODA_NOCACHE; goto exit; } error = venus_lookup(dir->i_sb, coda_i2f(dir), name, length, &type, &resfid); if (!error) error = coda_cnode_make(&inode, &resfid, dir->i_sb); if (error && error != -ENOENT) return ERR_PTR(error); exit: if (inode && (type & CODA_NOCACHE)) coda_flag_inode(inode, C_VATTR | C_PURGE); return d_splice_alias(inode, entry); }
/* try to make de an entry in dir_inodde linked to source_de */ static int coda_link(struct dentry *source_de, struct inode *dir_inode, struct dentry *de) { struct inode *inode = source_de->d_inode; const char * name = de->d_name.name; int len = de->d_name.len; int error; if (coda_isroot(dir_inode) && coda_iscontrol(name, len)) return -EPERM; error = venus_link(dir_inode->i_sb, coda_i2f(inode), coda_i2f(dir_inode), (const char *)name, len); if (error) { d_drop(de); return error; } coda_dir_update_mtime(dir_inode); ihold(inode); d_instantiate(de, inode); inc_nlink(inode); return 0; }
/* access routines: lookup, readlink, permission */ static struct dentry *coda_lookup(struct inode *dir, struct dentry *entry) { struct inode *res_inode = NULL; struct ViceFid resfid = {0,0,0}; int dropme = 0; /* to indicate entry should not be cached */ int type = 0; int error = 0; const char *name = entry->d_name.name; size_t length = entry->d_name.len; if ( length > CODA_MAXNAMLEN ) { printk("name too long: lookup, %s (%*s)\n", coda_i2s(dir), (int)length, name); return ERR_PTR(-ENAMETOOLONG); } CDEBUG(D_INODE, "name %s, len %ld in ino %ld, fid %s\n", name, (long)length, dir->i_ino, coda_i2s(dir)); /* control object, create inode on the fly */ if (coda_isroot(dir) && coda_iscontrol(name, length)) { error = coda_cnode_makectl(&res_inode, dir->i_sb); CDEBUG(D_SPECIAL, "Lookup on CTL object; dir ino %ld, count %d\n", dir->i_ino, atomic_read(&dir->i_count)); dropme = 1; goto exit; } error = venus_lookup(dir->i_sb, coda_i2f(dir), (const char *)name, length, &type, &resfid); res_inode = NULL; if (!error) { if (type & CODA_NOCACHE) { type &= (~CODA_NOCACHE); CDEBUG(D_INODE, "dropme set for %s\n", coda_f2s(&resfid)); dropme = 1; } error = coda_cnode_make(&res_inode, &resfid, dir->i_sb); if (error) return ERR_PTR(error); } else if (error != -ENOENT) { CDEBUG(D_INODE, "error for %s(%*s)%d\n", coda_i2s(dir), (int)length, name, error); return ERR_PTR(error); } CDEBUG(D_INODE, "lookup: %s is (%s), type %d result %d, dropme %d\n", name, coda_f2s(&resfid), type, error, dropme); exit: entry->d_time = 0; entry->d_op = &coda_dentry_operations; d_add(entry, res_inode); if ( dropme ) { d_drop(entry); coda_flag_inode(res_inode, C_VATTR); } return NULL; }