void ufs_put_inode (struct inode * inode) { if (inode->i_nlink) return; printk("ufs_put_inode: nlink == 0 for inum %lu on dev %d/%d\n", inode->i_ino, MAJOR(inode->i_dev), MINOR(inode->i_dev)); ufs_print_inode(inode); panic("ufs_put_inode: fs is read only, and nlink == 0"); /* XXX - this code goes here eventually inode->i_size = 0; if (inode->i_blocks) ufs_truncate(inode); ufs_free_inode(inode); */ return; }
/* XXX - ufs_read_inode is a mess */ void ufs_read_inode(struct inode * inode) { struct super_block * sb; struct ufs_inode * ufsip; struct buffer_head * bh; sb = inode->i_sb; if (ufs_ino_ok(inode)) { printk("ufs_read_inode: bad inum %lu", inode->i_ino); return; } #if 0 printk("ufs_read_inode: ino %lu cg %u cgino %u ipg %u inopb %u\n", inode->i_ino, ufs_ino2cg(inode), (inode->i_ino%sb->u.ufs_sb.s_inopb), sb->u.ufs_sb.s_ipg, sb->u.ufs_sb.s_inopb); #endif bh = bread(inode->i_dev, ufs_cgimin(inode->i_sb, ufs_ino2cg(inode)) + (inode->i_ino%sb->u.ufs_sb.s_ipg)/(sb->u.ufs_sb.s_inopb/sb->u.ufs_sb.s_fsfrag), BLOCK_SIZE); if (!bh) { printk("ufs_read_inode: can't read inode %lu from dev %d/%d", inode->i_ino, MAJOR(inode->i_dev), MINOR(inode->i_dev)); return; } ufsip = (struct ufs_inode *)bh->b_data; ufsip += (inode->i_ino%(sb->u.ufs_sb.s_inopb/sb->u.ufs_sb.s_fsfrag)); /* * Copy data to the in-core inode. */ inode->i_mode = ufsip->ui_mode; inode->i_nlink = ufsip->ui_nlink; if (inode->i_nlink == 0) { /* XXX */ printk("ufs_read_inode: zero nlink ino %lu dev %u/%u\n", inode->i_ino, MAJOR(inode->i_dev), MINOR(inode->i_dev)); inode->i_nlink = 1; printk("ufs_read_inode: fishy ino %lu pblk %lu dev %u/%u\n", inode->i_ino, ufs_cgimin(inode->i_sb, ufs_ino2cg(inode)) + (inode->i_ino%sb->u.ufs_sb.s_ipg)/sb->u.ufs_sb.s_inopb, MAJOR(inode->i_dev), MINOR(inode->i_dev)); } /* XXX - debugging */ if (ufsip->ui_gen == 0) { printk("ufs_read_inode: zero gen ino %lu pblk %lu dev %u/%u\n", inode->i_ino, ufs_cgimin(inode->i_sb, ufs_ino2cg(inode)) + (inode->i_ino%sb->u.ufs_sb.s_ipg)/sb->u.ufs_sb.s_inopb, MAJOR(inode->i_dev), MINOR(inode->i_dev)); } /* * Since Linux currently only has 16-bit uid_t and gid_t, we can't * really support EFTs. For the moment, we use 0 as the uid and gid * if an inode has a uid or gid that won't fit in 16 bits. This way * random users can't get at these files, since they get dynamically * "chown()ed" to root. */ if (ufsip->ui_suid == UFS_USEEFT) { /* EFT */ inode->i_uid = 0; printk("ufs_read_inode: EFT uid %u ino %lu dev %u/%u, using %u\n", ufsip->ui_uid, inode->i_ino, MAJOR(inode->i_dev), MINOR(inode->i_dev), inode->i_uid); } else { inode->i_uid = ufsip->ui_suid; } if (ufsip->ui_suid == UFS_USEEFT) { /* EFT */ inode->i_uid = 0; printk("ufs_read_inode: EFT gid %u ino %lu dev %u/%u, using %u\n", ufsip->ui_gid, inode->i_ino, MAJOR(inode->i_dev), MINOR(inode->i_dev), inode->i_gid); } else { inode->i_gid = ufsip->ui_sgid; } /* * Linux i_size is 32 bits, so some files on a UFS filesystem may not * be readable. I let people access the first 32 bits worth of them. * for the rw code, we may want to mark these inodes as read-only. * XXX - bug Linus to make i_size a __u64 instead of a __u32. */ inode->u.ufs_i.ui_size = ((__u64)(ufsip->ui_size.val[0])<<32) | (__u64)(ufsip->ui_size.val[1]); inode->i_size = ufsip->ui_size.val[1]; /* XXX - endianity */ if (ufsip->ui_size.val[0] != 0) { inode->i_size = 0xffffffff; printk("ufs_read_inode: file too big ino %lu dev %u/%u, faking size\n", inode->i_ino, MAJOR(inode->i_dev), MINOR(inode->i_dev)); } /* * Linux doesn't keep tv_usec around in the kernel, so we discard it. * XXX - I'm not sure what I should do about writing things. I may * want to keep this data, but for the moment I think I'll just write * zeros for these fields when writing out inodes. */ inode->i_atime = ufsip->ui_atime.tv_sec; inode->i_mtime = ufsip->ui_mtime.tv_sec; inode->i_ctime = ufsip->ui_ctime.tv_sec; inode->i_blksize = sb->u.ufs_sb.s_fsize; inode->i_blocks = ufsip->ui_blocks; inode->i_version = ++event; /* see linux/kernel/sched.c */ if (S_ISREG(inode->i_mode)) { inode->i_op = &ufs_file_inode_operations; } else if (S_ISDIR(inode->i_mode)) { inode->i_op = &ufs_dir_inode_operations; } else if (S_ISLNK(inode->i_mode)) { inode->i_op = &ufs_symlink_inode_operations; } else if (S_ISCHR(inode->i_mode)) { inode->i_op = &chrdev_inode_operations; } else if (S_ISBLK(inode->i_mode)) { inode->i_op = &blkdev_inode_operations; } else if (S_ISFIFO(inode->i_mode)) { init_fifo(inode); } else { printk("ufs_read_inode: unknown file type 0%o ino %lu dev %d/%d\n", inode->i_mode, inode->i_ino, MAJOR(inode->i_dev), MINOR(inode->i_dev)); /* XXX - debugging */ ufs_print_inode(inode); inode->i_op = &ufs_file_inode_operations; } /* * ufs_read_super makes sure that UFS_NDADDR and UFS_NINDIR are sane. */ if (S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode) || S_ISLNK(inode->i_mode)) { int i; for (i = 0; i < UFS_NDADDR; i++) { inode->u.ufs_i.ui_db[i] = ufsip->ui_db[i]; } for (i = 0; i < UFS_NINDIR; i++) { inode->u.ufs_i.ui_ib[i] = ufsip->ui_ib[i]; } } if (S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode)) { /* XXX - should be ui_db[1] on little endian ufs filesystems */ inode->i_rdev = to_kdev_t(ufsip->ui_db[0]); } /* XXX - implement fast and slow symlinks */ inode->u.ufs_i.ui_flags = ufsip->ui_flags; inode->u.ufs_i.ui_gen = ufsip->ui_gen; /* XXX - is this i_version? */ inode->u.ufs_i.ui_shadow = ufsip->ui_shadow; /* XXX */ inode->u.ufs_i.ui_uid = ufsip->ui_uid; inode->u.ufs_i.ui_gid = ufsip->ui_gid; inode->u.ufs_i.ui_oeftflag = ufsip->ui_oeftflag; brelse(bh); if (inode->i_sb->u.ufs_sb.s_flags & (UFS_DEBUG|UFS_DEBUG_INODE)) { ufs_print_inode(inode); } return; }
/* * This is blatantly stolen from ext2fs */ static int ufs_readdir (struct inode * inode, struct file * filp, void * dirent, filldir_t filldir) { int error = 0; unsigned long offset, lblk, blk; int i, stored; struct buffer_head * bh; struct ufs_direct * de; struct super_block * sb; if (!inode || !S_ISDIR(inode->i_mode)) return -EBADF; sb = inode->i_sb; if (inode->i_sb->u.ufs_sb.s_flags & UFS_DEBUG) { printk("ufs_readdir: ino %lu f_pos %lu\n", inode->i_ino, (unsigned long) filp->f_pos); ufs_print_inode(inode); } stored = 0; bh = NULL; offset = filp->f_pos & (sb->s_blocksize - 1); while (!error && !stored && filp->f_pos < inode->i_size) { lblk = (filp->f_pos) >> sb->s_blocksize_bits; blk = ufs_bmap(inode, lblk); /* XXX - ufs_bmap() call needs error checking */ blk = ufs_bmap(inode, lblk); bh = bread (sb->s_dev, blk, sb->s_blocksize); if (!bh) { /* XXX - error - skip to the next block */ printk("ufs_readdir: dir inode %lu has a hole at offset %lu\n", inode->i_ino, (unsigned long int)filp->f_pos); filp->f_pos += sb->s_blocksize - offset; continue; } revalidate: /* If the dir block has changed since the last call to * readdir(2), then we might be pointing to an invalid * dirent right now. Scan from the start of the block * to make sure. */ if (filp->f_version != inode->i_version) { for (i = 0; i < sb->s_blocksize && i < offset; ) { de = (struct ufs_direct *) (bh->b_data + i); /* It's too expensive to do a full * dirent test each time round this * loop, but we do have to test at * least that it is non-zero. A * failure will be detected in the * dirent test below. */ if (de->d_reclen < 1) break; i += de->d_reclen; } offset = i; filp->f_pos = (filp->f_pos & ~(sb->s_blocksize - 1)) | offset; filp->f_version = inode->i_version; } while (!error && filp->f_pos < inode->i_size && offset < sb->s_blocksize) { de = (struct ufs_direct *) (bh->b_data + offset); /* XXX - put in a real ufs_check_dir_entry() */ if ((de->d_reclen == 0) || (de->d_namlen == 0)) { filp->f_pos = (filp->f_pos & (sb->s_blocksize - 1)) + sb->s_blocksize; brelse(bh); return stored; } #if 0 if (!ext2_check_dir_entry ("ext2_readdir", inode, de, bh, offset)) { /* On error, skip the f_pos to the next block. */ filp->f_pos = (filp->f_pos & (sb->s_blocksize - 1)) + sb->s_blocksize; brelse (bh); return stored; } #endif /* XXX */ offset += de->d_reclen; if (de->d_ino) { /* We might block in the next section * if the data destination is * currently swapped out. So, use a * version stamp to detect whether or * not the directory has been modified * during the copy operation. */ unsigned long version; dcache_add(inode, de->d_name, de->d_namlen, de->d_ino); version = inode->i_version; if (inode->i_sb->u.ufs_sb.s_flags & UFS_DEBUG) { printk("ufs_readdir: filldir(%s,%u)\n", de->d_name, de->d_ino); } error = filldir(dirent, de->d_name, de->d_namlen, filp->f_pos, de->d_ino); if (error) break; if (version != inode->i_version) goto revalidate; stored ++; } filp->f_pos += de->d_reclen; } offset = 0; brelse (bh); } #if 0 /* XXX */ if (!IS_RDONLY(inode)) { inode->i_atime = CURRENT_TIME; inode->i_dirt = 1; } #endif /* XXX */ return 0; }