/* cnode related routines for the coda kernel code (C) 1996 Peter Braam */ #include #include #include #include #include #include #include extern int coda_debug; inline int coda_fideq(ViceFid *fid1, ViceFid *fid2) { if (fid1->Vnode != fid2->Vnode) return 0; if (fid1->Volume != fid2->Volume) return 0; if (fid1->Unique != fid2->Unique) return 0; return 1; } inline int coda_isnullfid(ViceFid *fid) { if (fid->Vnode || fid->Volume || fid->Unique) return 0; return 1; } static int coda_inocmp(struct inode *inode, unsigned long ino, void *opaque) { return (coda_fideq((ViceFid *)opaque, &(ITOC(inode)->c_fid))); } static struct inode_operations coda_symlink_inode_operations = { readlink: page_readlink, follow_link: page_follow_link, setattr: coda_notify_change, }; /* cnode.c */ static void coda_fill_inode(struct inode *inode, struct coda_vattr *attr) { CDEBUG(D_SUPER, "ino: %ld\n", inode->i_ino); if (coda_debug & D_SUPER ) print_vattr(attr); coda_vattr_to_iattr(inode, attr); if (S_ISREG(inode->i_mode)) { inode->i_op = &coda_file_inode_operations; inode->i_fop = &coda_file_operations; } else if (S_ISDIR(inode->i_mode)) { inode->i_op = &coda_dir_inode_operations; inode->i_fop = &coda_dir_operations; } else if (S_ISLNK(inode->i_mode)) { inode->i_op = &coda_symlink_inode_operations; inode->i_data.a_ops = &coda_symlink_aops; inode->i_mapping = &inode->i_data; } else init_special_inode(inode, inode->i_mode, attr->va_rdev); } struct inode * coda_iget(struct super_block * sb, ViceFid * fid, struct coda_vattr * attr) { struct inode *inode; struct coda_inode_info *cii; ino_t ino = coda_f2i(fid); struct coda_sb_info *sbi = coda_sbp(sb); down(&sbi->sbi_iget4_mutex); inode = iget4(sb, ino, coda_inocmp, fid); if ( !inode ) { CDEBUG(D_CNODE, "coda_iget: no inode\n"); up(&sbi->sbi_iget4_mutex); return ERR_PTR(-ENOMEM); } /* check if the inode is already initialized */ cii = ITOC(inode); if (coda_isnullfid(&cii->c_fid)) /* new, empty inode found... initializing */ cii->c_fid = *fid; up(&sbi->sbi_iget4_mutex); /* always replace the attributes, type might have changed */ coda_fill_inode(inode, attr); return inode; } /* this is effectively coda_iget: - get attributes (might be cached) - get the inode for the fid using vfs iget - link the two up if this is needed - fill in the attributes */ int coda_cnode_make(struct inode **inode, ViceFid *fid, struct super_block *sb) { struct coda_vattr attr; int error; /* We get inode numbers from Venus -- see venus source */ error = venus_getattr(sb, fid, &attr); if ( error ) { CDEBUG(D_CNODE, "coda_cnode_make: coda_getvattr returned %d for %s.\n", error, coda_f2s(fid)); *inode = NULL; return error; } *inode = coda_iget(sb, fid, &attr); if ( IS_ERR(*inode) ) { printk("coda_cnode_make: coda_iget failed\n"); return PTR_ERR(*inode); } CDEBUG(D_DOWNCALL, "Done making inode: ino %ld, count %d with %s\n", (*inode)->i_ino, atomic_read(&(*inode)->i_count), coda_f2s(&ITOC(*inode)->c_fid)); return 0; } void coda_replace_fid(struct inode *inode, struct ViceFid *oldfid, struct ViceFid *newfid) { struct coda_inode_info *cii; cii = ITOC(inode); if (!coda_fideq(&cii->c_fid, oldfid)) BUG(); /* replace fid and rehash inode */ /* XXX we probably need to hold some lock here! */ remove_inode_hash(inode); cii->c_fid = *newfid; inode->i_ino = coda_f2i(newfid); insert_inode_hash(inode); } /* convert a fid to an inode. */ struct inode *coda_fid_to_inode(ViceFid *fid, struct super_block *sb) { ino_t nr; struct inode *inode; struct coda_inode_info *cii; struct coda_sb_info *sbi; if ( !sb ) { printk("coda_fid_to_inode: no sb!\n"); return NULL; } CDEBUG(D_INODE, "%s\n", coda_f2s(fid)); sbi = coda_sbp(sb); nr = coda_f2i(fid); down(&sbi->sbi_iget4_mutex); inode = iget4(sb, nr, coda_inocmp, fid); if ( !inode ) { printk("coda_fid_to_inode: null from iget, sb %p, nr %ld.\n", sb, (long)nr); goto out_unlock; } cii = ITOC(inode); /* The inode could already be purged due to memory pressure */ if (coda_isnullfid(&cii->c_fid)) { inode->i_nlink = 0; iput(inode); goto out_unlock; } CDEBUG(D_INODE, "found %ld\n", inode->i_ino); up(&sbi->sbi_iget4_mutex); return inode; out_unlock: up(&sbi->sbi_iget4_mutex); return NULL; } /* the CONTROL inode is made without asking attributes from Venus */ int coda_cnode_makectl(struct inode **inode, struct super_block *sb) { int error = 0; *inode = iget(sb, CTL_INO); if ( *inode ) { (*inode)->i_op = &coda_ioctl_inode_operations; (*inode)->i_fop = &coda_ioctl_operations; (*inode)->i_mode = 0444; error = 0; } else { error = -ENOMEM; } return error; }