⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 inode.c

📁 《嵌入式系统设计与实例开发实验教材二源码》Linux内核移植与编译实验
💻 C
字号:
/* *  linux/fs/umsdos/inode.c * *      Written 1993 by Jacques Gelinas *      Inspired from linux/fs/msdos/... by Werner Almesberger */#include <linux/module.h>#include <linux/init.h>#include <linux/fs.h>#include <linux/msdos_fs.h>#include <linux/kernel.h>#include <linux/sched.h>#include <linux/errno.h>#include <asm/uaccess.h>#include <linux/string.h>#include <linux/stat.h>#include <linux/umsdos_fs.h>#include <linux/list.h>#include <linux/pagemap.h>extern struct dentry_operations umsdos_dentry_operations;struct dentry *saved_root;	/* Original root if changed */struct inode *pseudo_root;	/* Useful to simulate the pseudo DOS */					/* directory. See UMSDOS_readdir_x() */static struct dentry *check_pseudo_root(struct super_block *);void UMSDOS_put_inode (struct inode *inode){	PRINTK ((KERN_DEBUG 		"put inode %p (%lu) pos %lu count=%d\n"		 ,inode, inode->i_ino		 ,inode->u.umsdos_i.pos		 ,atomic_read(&inode->i_count)));	if (inode == pseudo_root) {		Printk ((KERN_ERR "Umsdos: debug: releasing pseudo_root - ino=%lu count=%d\n", inode->i_ino, atomic_read(&inode->i_count)));	}	if (atomic_read(&inode->i_count) == 1)		inode->u.umsdos_i.i_patched = 0;}void UMSDOS_put_super (struct super_block *sb){	Printk ((KERN_DEBUG "UMSDOS_put_super: entering\n"));	if (saved_root && pseudo_root && sb->s_dev == ROOT_DEV) {		shrink_dcache_parent(saved_root);		dput(saved_root);		saved_root = NULL;		pseudo_root = NULL;	}	msdos_put_super (sb);}/* * Complete the setup of a directory dentry based on its * EMD/non-EMD status.  If it has an EMD, then plug the * umsdos function table. If not, use the msdos one. */void umsdos_setup_dir(struct dentry *dir){	struct inode *inode = dir->d_inode;	if (!S_ISDIR(inode->i_mode))		printk(KERN_ERR "umsdos_setup_dir: %s/%s not a dir!\n",			dir->d_parent->d_name.name, dir->d_name.name);	init_waitqueue_head (&inode->u.umsdos_i.dir_info.p);	inode->u.umsdos_i.dir_info.looking = 0;	inode->u.umsdos_i.dir_info.creating = 0;	inode->u.umsdos_i.dir_info.pid = 0;	inode->i_op = &umsdos_rdir_inode_operations;	inode->i_fop = &umsdos_rdir_operations;	if (umsdos_have_emd(dir)) {Printk((KERN_DEBUG "umsdos_setup_dir: %s/%s using EMD\n",dir->d_parent->d_name.name, dir->d_name.name));		inode->i_op = &umsdos_dir_inode_operations;		inode->i_fop = &umsdos_dir_operations;	}}/* * Add some info into an inode so it can find its owner quickly */void umsdos_set_dirinfo_new (struct dentry *dentry, off_t f_pos){	struct inode *inode = dentry->d_inode;	struct dentry *demd;	inode->u.umsdos_i.pos = f_pos;	/* now check the EMD file */	demd = umsdos_get_emd_dentry(dentry->d_parent);	if (!IS_ERR(demd)) {		dput(demd);	}	return;}static struct inode_operations umsdos_file_inode_operations = {	truncate:	fat_truncate,	setattr:	UMSDOS_notify_change,};static struct inode_operations umsdos_symlink_inode_operations = {	readlink:	page_readlink,	follow_link:	page_follow_link,	setattr:	UMSDOS_notify_change,};/* * Connect the proper tables in the inode and add some info. *//* #Specification: inode / umsdos info * The first time an inode is seen (inode->i_count == 1), * the inode number of the EMD file which controls this inode * is tagged to this inode. It allows operations such as * notify_change to be handled. */void umsdos_patch_dentry_inode(struct dentry *dentry, off_t f_pos){	struct inode *inode = dentry->d_inode;PRINTK (("umsdos_patch_dentry_inode: inode=%lu\n", inode->i_ino));	/*	 * Classify the inode based on EMD/non-EMD status.	 */PRINTK (("umsdos_patch_inode: call umsdos_set_dirinfo_new(%p,%lu)\n",dentry, f_pos));	umsdos_set_dirinfo_new(dentry, f_pos);	inode->i_op = &umsdos_file_inode_operations;	if (S_ISREG (inode->i_mode)) {		/* address_space operations already set */	} else if (S_ISDIR (inode->i_mode)) {		umsdos_setup_dir(dentry);	} else if (S_ISLNK (inode->i_mode)) {		/* address_space operations already set */		inode->i_op = &umsdos_symlink_inode_operations;	} else		init_special_inode(inode, inode->i_mode,					kdev_t_to_nr(inode->i_rdev));}/* * lock the parent dir before starting ... * also handles hardlink converting */int UMSDOS_notify_change (struct dentry *dentry, struct iattr *attr){	struct inode *dir, *inode;	struct umsdos_info info;	struct dentry *temp, *old_dentry = NULL;	int ret;	ret = umsdos_parse (dentry->d_name.name, dentry->d_name.len,				&info);	if (ret)		goto out;	ret = umsdos_findentry (dentry->d_parent, &info, 0);	if (ret) {printk("UMSDOS_notify_change: %s/%s not in EMD, ret=%d\n",dentry->d_parent->d_name.name, dentry->d_name.name, ret);		goto out;	}	if (info.entry.flags & UMSDOS_HLINK) {		/*		 * In order to get the correct (real) inode, we just drop		 * the original dentry.		 */ 		d_drop(dentry);Printk(("UMSDOS_notify_change: hard link %s/%s, fake=%s\n",dentry->d_parent->d_name.name, dentry->d_name.name, info.fake.fname));			/* Do a real lookup to get the short name dentry */		temp = umsdos_covered(dentry->d_parent, info.fake.fname,						info.fake.len);		ret = PTR_ERR(temp);		if (IS_ERR(temp))			goto out;			/* now resolve the link ... */		temp = umsdos_solve_hlink(temp);		ret = PTR_ERR(temp);		if (IS_ERR(temp))			goto out;		old_dentry = dentry;		dentry = temp;	/* so umsdos_notify_change_locked will operate on that */	}	dir = dentry->d_parent->d_inode;	inode = dentry->d_inode;	ret = inode_change_ok (inode, attr);	if (ret)		goto out;	down(&dir->i_sem);	ret = umsdos_notify_change_locked(dentry, attr);	up(&dir->i_sem);	if (ret == 0)		ret = inode_setattr (inode, attr);out:	if (old_dentry)		dput (dentry);	/* if we had to use fake dentry for hardlinks, dput() it now */	return ret;}/* * Must be called with the parent lock held. */int umsdos_notify_change_locked(struct dentry *dentry, struct iattr *attr){	struct inode *inode = dentry->d_inode;	struct dentry *demd;	struct address_space *mapping;	struct page *page;	int ret = 0;	struct umsdos_dirent *entry;	int offs;Printk(("UMSDOS_notify_change: entering for %s/%s (%d)\n",dentry->d_parent->d_name.name, dentry->d_name.name, inode->u.umsdos_i.i_patched));	if (inode->i_nlink == 0)		goto out;	if (inode->i_ino == UMSDOS_ROOT_INO)		goto out;	/* get the EMD file dentry */	demd = umsdos_get_emd_dentry(dentry->d_parent);	ret = PTR_ERR(demd);	if (IS_ERR(demd))		goto out;	ret = 0;	/* don't do anything if directory is not promoted to umsdos yet */	if (!demd->d_inode) { 		Printk((KERN_DEBUG			"UMSDOS_notify_change: no EMD file %s/%s\n",			demd->d_parent->d_name.name, demd->d_name.name));		goto out_dput;	}	/* don't do anything if this is the EMD itself */	if (inode == demd->d_inode)		goto out_dput;	/* This inode is not a EMD file nor an inode used internally	 * by MSDOS, so we can update its status.	 * See emd.c	 */	/* Read only the start of the entry since we don't touch the name */	mapping = demd->d_inode->i_mapping;	offs = inode->u.umsdos_i.pos & ~PAGE_CACHE_MASK;	ret = -ENOMEM;	page=grab_cache_page(mapping,inode->u.umsdos_i.pos>>PAGE_CACHE_SHIFT);	if (!page)		goto out_dput;	ret=mapping->a_ops->prepare_write(NULL,page,offs,offs+UMSDOS_REC_SIZE);	if (ret)		goto out_unlock;	entry = (struct umsdos_dirent *) (page_address(page) + offs);	if (attr->ia_valid & ATTR_UID)		entry->uid = cpu_to_le16(attr->ia_uid);	if (attr->ia_valid & ATTR_GID)		entry->gid = cpu_to_le16(attr->ia_gid);	if (attr->ia_valid & ATTR_MODE)		entry->mode = cpu_to_le16(attr->ia_mode);	if (attr->ia_valid & ATTR_ATIME)		entry->atime = cpu_to_le32(attr->ia_atime);	if (attr->ia_valid & ATTR_MTIME)		entry->mtime = cpu_to_le32(attr->ia_mtime);	if (attr->ia_valid & ATTR_CTIME)		entry->ctime = cpu_to_le32(attr->ia_ctime);	entry->nlink = cpu_to_le16(inode->i_nlink);	ret=mapping->a_ops->commit_write(NULL,page,offs,offs+UMSDOS_REC_SIZE);	if (ret)		printk(KERN_WARNING			"umsdos_notify_change: %s/%s EMD write error, ret=%d\n",			dentry->d_parent->d_name.name, dentry->d_name.name,ret);	/* #Specification: notify_change / msdos fs	 * notify_change operation are done only on the	 * EMD file. The msdos fs is not even called.	 */out_unlock:	UnlockPage(page);	page_cache_release(page);out_dput:	dput(demd);out:	return ret;}/* * Update the disk with the inode content */void UMSDOS_write_inode (struct inode *inode, int wait){	struct iattr newattrs;	fat_write_inode (inode, wait);	newattrs.ia_mtime = inode->i_mtime;	newattrs.ia_atime = inode->i_atime;	newattrs.ia_ctime = inode->i_ctime;	newattrs.ia_valid = ATTR_MTIME | ATTR_ATIME | ATTR_CTIME;	/*	 * UMSDOS_notify_change is convenient to call here	 * to update the EMD entry associated with this inode.	 * But it has the side effect to re"dirt" the inode.	 *//*       * UMSDOS_notify_change (inode, &newattrs); * inode->i_state &= ~I_DIRTY; / * FIXME: this doesn't work.  We need to remove ourselves from list on dirty inodes. /mn/ */}static struct super_operations umsdos_sops ={	write_inode:	UMSDOS_write_inode,	put_inode:	UMSDOS_put_inode,	delete_inode:	fat_delete_inode,	put_super:	UMSDOS_put_super,	statfs:		UMSDOS_statfs,	clear_inode:	fat_clear_inode,};int UMSDOS_statfs(struct super_block *sb,struct statfs *buf){	int ret;	ret = fat_statfs (sb, buf);	if (!ret)			buf->f_namelen = UMSDOS_MAXNAME;	return ret;}/* * Read the super block of an Extended MS-DOS FS. */struct super_block *UMSDOS_read_super (struct super_block *sb, void *data,				      int silent){	struct super_block *res;	struct dentry *new_root;	/*	 * Call msdos-fs to mount the disk.	 * Note: this returns res == sb or NULL	 */	res = msdos_read_super (sb, data, silent);	if (!res)		goto out_fail;	printk (KERN_INFO "UMSDOS 0.86k "		"(compatibility level %d.%d, fast msdos)\n", 		UMSDOS_VERSION, UMSDOS_RELEASE);	sb->s_op = &umsdos_sops;	MSDOS_SB(sb)->options.dotsOK = 0;	/* disable hidden==dotfile */	/* install our dentry operations ... */	sb->s_root->d_op = &umsdos_dentry_operations;	umsdos_patch_dentry_inode(sb->s_root, 0);	/* Check whether to change to the /linux root */	new_root = check_pseudo_root(sb);	if (new_root) {		/* sanity check */		if (new_root->d_op != &umsdos_dentry_operations)			printk("umsdos_read_super: pseudo-root wrong ops!\n");		pseudo_root = new_root->d_inode;		saved_root = sb->s_root;		printk(KERN_INFO "UMSDOS: changed to alternate root\n");		dget (sb->s_root); sb->s_root = dget(new_root);	}	return sb;out_fail:	printk(KERN_INFO "UMSDOS: msdos_read_super failed, mount aborted.\n");	return NULL;}/* * Check for an alternate root if we're the root device. */extern kdev_t ROOT_DEV;static struct dentry *check_pseudo_root(struct super_block *sb){	struct dentry *root, *sbin, *init;	/*	 * Check whether we're mounted as the root device.	 * must check like this, because we can be used with initrd	 */			if (sb->s_dev != ROOT_DEV)		goto out_noroot;	/* 	 * lookup_dentry needs a (so far non-existent) root. 	 */	printk(KERN_INFO "check_pseudo_root: mounted as root\n");	root = lookup_one_len(UMSDOS_PSDROOT_NAME, sb->s_root,UMSDOS_PSDROOT_LEN); 	if (IS_ERR(root))		goto out_noroot;			if (!root->d_inode || !S_ISDIR(root->d_inode->i_mode))		goto out_dput;printk(KERN_INFO "check_pseudo_root: found %s/%s\n",root->d_parent->d_name.name, root->d_name.name);	/* look for /sbin/init */	sbin = lookup_one_len("sbin", root, 4);	if (IS_ERR(sbin))		goto out_dput;	if (!sbin->d_inode || !S_ISDIR(sbin->d_inode->i_mode))		goto out_dput_sbin;	init = lookup_one_len("init", sbin, 4);	if (IS_ERR(init))		goto out_dput_sbin;	if (!init->d_inode)		goto out_dput_init;	printk(KERN_INFO "check_pseudo_root: found %s/%s, enabling pseudo-root\n", init->d_parent->d_name.name, init->d_name.name);	dput(sbin);	dput(init);	return root;	/* Alternate root not found ... */out_dput_init:	dput(init);out_dput_sbin:	dput(sbin);out_dput:	dput(root);out_noroot:	return NULL;}static DECLARE_FSTYPE_DEV(umsdos_fs_type, "umsdos", UMSDOS_read_super);static int __init init_umsdos_fs (void){	return register_filesystem (&umsdos_fs_type);}static void __exit exit_umsdos_fs (void){	unregister_filesystem (&umsdos_fs_type);}EXPORT_NO_SYMBOLS;module_init(init_umsdos_fs)module_exit(exit_umsdos_fs)MODULE_LICENSE("GPL");

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -