/* 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; coda_vfs_stat.link++; if (coda_isroot(dir_inode) && coda_iscontrol(name, len)) return -EPERM; CDEBUG(D_INODE, "old: fid: %s\n", coda_i2s(inode)); CDEBUG(D_INODE, "directory: %s\n", coda_i2s(dir_inode)); error = venus_link(dir_inode->i_sb, coda_i2f(inode), coda_i2f(dir_inode), (const char *)name, len); if (error) { d_drop(de); goto out; } coda_dir_changed(dir_inode, 0); atomic_inc(&inode->i_count); d_instantiate(de, inode); inode->i_nlink++; out: CDEBUG(D_INODE, "link result %d\n",error); return(error); }
/* access routines: lookup, readlink, permission */ static struct dentry *coda_lookup(struct inode *dir, struct dentry *entry, struct nameidata *nd) { struct super_block *sb = dir->i_sb; const char *name = entry->d_name.name; size_t length = entry->d_name.len; struct inode *inode; int type = 0; 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)) { inode = coda_cnode_makectl(sb); type = CODA_NOCACHE; } else { struct CodaFid fid = { { 0, } }; int error = venus_lookup(sb, coda_i2f(dir), name, length, &type, &fid); inode = !error ? coda_cnode_make(&fid, sb) : ERR_PTR(error); } if (!IS_ERR(inode) && (type & CODA_NOCACHE)) coda_flag_inode(inode, C_VATTR | C_PURGE); if (inode == ERR_PTR(-ENOENT)) inode = NULL; return d_splice_alias(inode, entry); }
int coda_permission(struct inode *inode, int mask) { int error; coda_vfs_stat.permission++; if ( mask == 0 ) return 0; if ( coda_access_cache ) { coda_permission_stat.count++; if ( coda_cache_check(inode, mask) ) { coda_permission_stat.hit_count++; return 0; } } CDEBUG(D_INODE, "mask is %o\n", mask); error = venus_access(inode->i_sb, coda_i2f(inode), mask); CDEBUG(D_INODE, "fid: %s, ino: %ld (mask: %o) error: %d\n", coda_i2s(inode), inode->i_ino, mask, error); if (!error) coda_cache_enter(inode, mask); return error; }
/* access routines: lookup, readlink, permission */ static struct dentry *coda_lookup(struct inode *dir, struct dentry *entry, struct nameidata *nd) { struct inode *res_inode = NULL; struct CodaFid resfid = { { 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); } lock_kernel(); /* control object, create inode on the fly */ if (coda_isroot(dir) && coda_iscontrol(name, length)) { error = coda_cnode_makectl(&res_inode, dir->i_sb); 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); dropme = 1; } error = coda_cnode_make(&res_inode, &resfid, dir->i_sb); if (error) { unlock_kernel(); return ERR_PTR(error); } } else if (error != -ENOENT) { unlock_kernel(); return ERR_PTR(error); } 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); } unlock_kernel(); return NULL; }
/* 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; } lock_kernel(); error = venus_lookup(dir->i_sb, coda_i2f(dir), name, length, &type, &resfid); if (!error) error = coda_cnode_make(&inode, &resfid, dir->i_sb); unlock_kernel(); if (error && error != -ENOENT) return ERR_PTR(error); exit: entry->d_op = &coda_dentry_operations; if (inode && (type & CODA_NOCACHE)) coda_flag_inode(inode, C_VATTR | C_PURGE); return d_splice_alias(inode, entry); }
static int coda_mkdir(struct inode *dir, struct dentry *de, int mode) { struct inode *inode; struct coda_vattr attrs; const char *name = de->d_name.name; int len = de->d_name.len; int error; struct ViceFid newfid; coda_vfs_stat.mkdir++; if (coda_isroot(dir) && coda_iscontrol(name, len)) return -EPERM; CDEBUG(D_INODE, "mkdir %s (len %d) in %s, mode %o.\n", name, len, coda_i2s(dir), mode); attrs.va_mode = mode; error = venus_mkdir(dir->i_sb, coda_i2f(dir), name, len, &newfid, &attrs); if ( error ) { CDEBUG(D_INODE, "mkdir error: %s result %d\n", coda_f2s(&newfid), error); d_drop(de); return error; } CDEBUG(D_INODE, "mkdir: new dir has fid %s.\n", coda_f2s(&newfid)); 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, 1); d_instantiate(de, inode); return 0; }
/* destruction routines: unlink, rmdir */ int coda_unlink(struct inode *dir, struct dentry *de) { int error; const char *name = de->d_name.name; int len = de->d_name.len; coda_vfs_stat.unlink++; CDEBUG(D_INODE, " %s in %s, dirino %ld\n", name , coda_i2s(dir), dir->i_ino); error = venus_remove(dir->i_sb, coda_i2f(dir), name, len); if ( error ) { CDEBUG(D_INODE, "upc returned error %d\n", error); return error; } coda_dir_changed(dir, 0); de->d_inode->i_nlink--; 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; }