11da177e4SLinus Torvalds /* 21da177e4SLinus Torvalds * namei.c 31da177e4SLinus Torvalds * 41da177e4SLinus Torvalds * Copyright (c) 1999 Al Smith 51da177e4SLinus Torvalds * 61da177e4SLinus Torvalds * Portions derived from work (c) 1995,1996 Christian Vogelgsang. 71da177e4SLinus Torvalds */ 81da177e4SLinus Torvalds 91da177e4SLinus Torvalds #include <linux/buffer_head.h> 101da177e4SLinus Torvalds #include <linux/string.h> 111da177e4SLinus Torvalds #include <linux/smp_lock.h> 1205da0804SChristoph Hellwig #include <linux/exportfs.h> 1345254b4fSChristoph Hellwig #include "efs.h" 1405da0804SChristoph Hellwig 151da177e4SLinus Torvalds 161da177e4SLinus Torvalds static efs_ino_t efs_find_entry(struct inode *inode, const char *name, int len) { 171da177e4SLinus Torvalds struct buffer_head *bh; 181da177e4SLinus Torvalds 191da177e4SLinus Torvalds int slot, namelen; 201da177e4SLinus Torvalds char *nameptr; 211da177e4SLinus Torvalds struct efs_dir *dirblock; 221da177e4SLinus Torvalds struct efs_dentry *dirslot; 231da177e4SLinus Torvalds efs_ino_t inodenum; 241da177e4SLinus Torvalds efs_block_t block; 251da177e4SLinus Torvalds 261da177e4SLinus Torvalds if (inode->i_size & (EFS_DIRBSIZE-1)) 271da177e4SLinus Torvalds printk(KERN_WARNING "EFS: WARNING: find_entry(): directory size not a multiple of EFS_DIRBSIZE\n"); 281da177e4SLinus Torvalds 291da177e4SLinus Torvalds for(block = 0; block < inode->i_blocks; block++) { 301da177e4SLinus Torvalds 311da177e4SLinus Torvalds bh = sb_bread(inode->i_sb, efs_bmap(inode, block)); 321da177e4SLinus Torvalds if (!bh) { 331da177e4SLinus Torvalds printk(KERN_ERR "EFS: find_entry(): failed to read dir block %d\n", block); 341da177e4SLinus Torvalds return 0; 351da177e4SLinus Torvalds } 361da177e4SLinus Torvalds 371da177e4SLinus Torvalds dirblock = (struct efs_dir *) bh->b_data; 381da177e4SLinus Torvalds 391da177e4SLinus Torvalds if (be16_to_cpu(dirblock->magic) != EFS_DIRBLK_MAGIC) { 401da177e4SLinus Torvalds printk(KERN_ERR "EFS: find_entry(): invalid directory block\n"); 411da177e4SLinus Torvalds brelse(bh); 421da177e4SLinus Torvalds return(0); 431da177e4SLinus Torvalds } 441da177e4SLinus Torvalds 451da177e4SLinus Torvalds for(slot = 0; slot < dirblock->slots; slot++) { 461da177e4SLinus Torvalds dirslot = (struct efs_dentry *) (((char *) bh->b_data) + EFS_SLOTAT(dirblock, slot)); 471da177e4SLinus Torvalds 481da177e4SLinus Torvalds namelen = dirslot->namelen; 491da177e4SLinus Torvalds nameptr = dirslot->name; 501da177e4SLinus Torvalds 511da177e4SLinus Torvalds if ((namelen == len) && (!memcmp(name, nameptr, len))) { 521da177e4SLinus Torvalds inodenum = be32_to_cpu(dirslot->inode); 531da177e4SLinus Torvalds brelse(bh); 541da177e4SLinus Torvalds return(inodenum); 551da177e4SLinus Torvalds } 561da177e4SLinus Torvalds } 571da177e4SLinus Torvalds brelse(bh); 581da177e4SLinus Torvalds } 591da177e4SLinus Torvalds return(0); 601da177e4SLinus Torvalds } 611da177e4SLinus Torvalds 621da177e4SLinus Torvalds struct dentry *efs_lookup(struct inode *dir, struct dentry *dentry, struct nameidata *nd) { 631da177e4SLinus Torvalds efs_ino_t inodenum; 641da177e4SLinus Torvalds struct inode * inode = NULL; 651da177e4SLinus Torvalds 661da177e4SLinus Torvalds lock_kernel(); 671da177e4SLinus Torvalds inodenum = efs_find_entry(dir, dentry->d_name.name, dentry->d_name.len); 681da177e4SLinus Torvalds if (inodenum) { 69298384cdSDavid Howells inode = efs_iget(dir->i_sb, inodenum); 70298384cdSDavid Howells if (IS_ERR(inode)) { 711da177e4SLinus Torvalds unlock_kernel(); 72298384cdSDavid Howells return ERR_CAST(inode); 731da177e4SLinus Torvalds } 741da177e4SLinus Torvalds } 751da177e4SLinus Torvalds unlock_kernel(); 761da177e4SLinus Torvalds 772d8a10cdSAl Viro return d_splice_alias(inode, dentry); 781da177e4SLinus Torvalds } 791da177e4SLinus Torvalds 8005da0804SChristoph Hellwig static struct inode *efs_nfs_get_inode(struct super_block *sb, u64 ino, 8105da0804SChristoph Hellwig u32 generation) 825ca29607SChristoph Hellwig { 835ca29607SChristoph Hellwig struct inode *inode; 845ca29607SChristoph Hellwig 855ca29607SChristoph Hellwig if (ino == 0) 865ca29607SChristoph Hellwig return ERR_PTR(-ESTALE); 87298384cdSDavid Howells inode = efs_iget(sb, ino); 88298384cdSDavid Howells if (IS_ERR(inode)) 89298384cdSDavid Howells return ERR_CAST(inode); 905ca29607SChristoph Hellwig 91298384cdSDavid Howells if (generation && inode->i_generation != generation) { 925ca29607SChristoph Hellwig iput(inode); 9305da0804SChristoph Hellwig return ERR_PTR(-ESTALE); 9405da0804SChristoph Hellwig } 9505da0804SChristoph Hellwig 9605da0804SChristoph Hellwig return inode; 9705da0804SChristoph Hellwig } 9805da0804SChristoph Hellwig 9905da0804SChristoph Hellwig struct dentry *efs_fh_to_dentry(struct super_block *sb, struct fid *fid, 10005da0804SChristoph Hellwig int fh_len, int fh_type) 10105da0804SChristoph Hellwig { 10205da0804SChristoph Hellwig return generic_fh_to_dentry(sb, fid, fh_len, fh_type, 10305da0804SChristoph Hellwig efs_nfs_get_inode); 10405da0804SChristoph Hellwig } 10505da0804SChristoph Hellwig 10605da0804SChristoph Hellwig struct dentry *efs_fh_to_parent(struct super_block *sb, struct fid *fid, 10705da0804SChristoph Hellwig int fh_len, int fh_type) 10805da0804SChristoph Hellwig { 10905da0804SChristoph Hellwig return generic_fh_to_parent(sb, fid, fh_len, fh_type, 11005da0804SChristoph Hellwig efs_nfs_get_inode); 1115ca29607SChristoph Hellwig } 1125ca29607SChristoph Hellwig 1131da177e4SLinus Torvalds struct dentry *efs_get_parent(struct dentry *child) 1141da177e4SLinus Torvalds { 11544003728SChristoph Hellwig struct dentry *parent = ERR_PTR(-ENOENT); 1161da177e4SLinus Torvalds efs_ino_t ino; 1171da177e4SLinus Torvalds 1181da177e4SLinus Torvalds lock_kernel(); 1191da177e4SLinus Torvalds ino = efs_find_entry(child->d_inode, "..", 2); 12044003728SChristoph Hellwig if (ino) 12144003728SChristoph Hellwig parent = d_obtain_alias(efs_iget(child->d_inode->i_sb, ino)); 1221da177e4SLinus Torvalds unlock_kernel(); 12344003728SChristoph Hellwig 1241da177e4SLinus Torvalds return parent; 1251da177e4SLinus Torvalds } 126