?? inode.c
字號:
/* * linux/fs/inode.c * * Copyright (C) 1991, 1992 Linus Torvalds */#include <linux/stat.h>#include <linux/sched.h>#include <linux/kernel.h>#include <linux/mm.h>#include <linux/string.h>#include <asm/system.h>#define NR_IHASH 512/* * Be VERY careful when you access the inode hash table. There * are some rather scary race conditions you need to take care of: * - P1 tries to open file "xx", calls "iget()" with the proper * inode number, but blocks because it's not on the list. * - P2 deletes file "xx", gets the inode (which P1 has just read, * but P1 hasn't woken up to the fact yet) * - P2 iput()'s the inode, which now has i_nlink = 0 * - P1 wakes up and has the inode, but now P2 has made that * inode invalid (but P1 has no way of knowing that). * * The "updating" counter makes sure that when P1 blocks on the * iget(), P2 can't delete the inode from under it because P2 * will wait until P1 has been able to update the inode usage * count so that the inode will stay in use until everybody has * closed it.. */static struct inode_hash_entry { struct inode * inode; int updating;} hash_table[NR_IHASH];static struct inode * first_inode;static struct wait_queue * inode_wait = NULL;/* Keep these next two contiguous in memory for sysctl.c */int nr_inodes = 0, nr_free_inodes = 0;int max_inodes = NR_INODE;static inline int const hashfn(kdev_t dev, unsigned int i){ return (HASHDEV(dev) ^ i) % NR_IHASH;}static inline struct inode_hash_entry * const hash(kdev_t dev, int i){ return hash_table + hashfn(dev, i);}static inline void insert_inode_free(struct inode *inode){ struct inode * prev, * next = first_inode; first_inode = inode; prev = next->i_prev; inode->i_next = next; inode->i_prev = prev; prev->i_next = inode; next->i_prev = inode;}static inline void remove_inode_free(struct inode *inode){ if (first_inode == inode) first_inode = first_inode->i_next; if (inode->i_next) inode->i_next->i_prev = inode->i_prev; if (inode->i_prev) inode->i_prev->i_next = inode->i_next; inode->i_next = inode->i_prev = NULL;}void insert_inode_hash(struct inode *inode){ struct inode_hash_entry *h; h = hash(inode->i_dev, inode->i_ino); inode->i_hash_next = h->inode; inode->i_hash_prev = NULL; if (inode->i_hash_next) inode->i_hash_next->i_hash_prev = inode; h->inode = inode;}static inline void remove_inode_hash(struct inode *inode){ struct inode_hash_entry *h; h = hash(inode->i_dev, inode->i_ino); if (h->inode == inode) h->inode = inode->i_hash_next; if (inode->i_hash_next) inode->i_hash_next->i_hash_prev = inode->i_hash_prev; if (inode->i_hash_prev) inode->i_hash_prev->i_hash_next = inode->i_hash_next; inode->i_hash_prev = inode->i_hash_next = NULL;}static inline void put_last_free(struct inode *inode){ remove_inode_free(inode); inode->i_prev = first_inode->i_prev; inode->i_prev->i_next = inode; inode->i_next = first_inode; inode->i_next->i_prev = inode;}int grow_inodes(void){ struct inode * inode; int i; if (!(inode = (struct inode*) get_free_page(GFP_KERNEL))) return -ENOMEM; i=PAGE_SIZE / sizeof(struct inode); nr_inodes += i; nr_free_inodes += i; if (!first_inode) inode->i_next = inode->i_prev = first_inode = inode++, i--; for ( ; i ; i-- ) insert_inode_free(inode++); return 0;}unsigned long inode_init(unsigned long start, unsigned long end){ memset(hash_table, 0, sizeof(hash_table)); first_inode = NULL; return start;}static void __wait_on_inode(struct inode *);static inline void wait_on_inode(struct inode * inode){ if (inode->i_lock) __wait_on_inode(inode);}static inline void lock_inode(struct inode * inode){ wait_on_inode(inode); inode->i_lock = 1;}static inline void unlock_inode(struct inode * inode){ inode->i_lock = 0; wake_up(&inode->i_wait);}/* * Note that we don't want to disturb any wait-queues when we discard * an inode. * * Argghh. Got bitten by a gcc problem with inlining: no way to tell * the compiler that the inline asm function 'memset' changes 'inode'. * I've been searching for the bug for days, and was getting desperate. * Finally looked at the assembler output... Grrr. * * The solution is the weird use of 'volatile'. Ho humm. Have to report * it to the gcc lists, and hope we can do this more cleanly some day.. */void clear_inode(struct inode * inode){ struct wait_queue * wait; /* * We can clear inodes either when a last deref to the inode * causes it to be deleted (reference count==1), or when we want to * reuse it (reference count==0). Any other count is an error. */ if (inode->i_count > 1) panic ("clear_inode: Inode still has references"); /* * We are about to zap this inode. This operation may block, * and it's imperative that we don't allow another process to * grab it before it is completely pulled down. The i_count * will prevent reuse of the inode by get_empty_inode(), but the * i_condemned flag will also prevent __iget() from finding the * inode until it is completely dead. */ inode->i_condemned = 1; inode->i_count++; truncate_inode_pages(inode, 0); wait_on_inode(inode); if (IS_WRITABLE(inode)) { if (inode->i_sb && inode->i_sb->dq_op) inode->i_sb->dq_op->drop(inode); } remove_inode_hash(inode); remove_inode_free(inode); wait = ((volatile struct inode *) inode)->i_wait; if (--inode->i_count) nr_free_inodes++; memset(inode,0,sizeof(*inode)); ((volatile struct inode *) inode)->i_wait = wait; insert_inode_free(inode); /* * The inode is now reusable again, and the condemned flag is * clear. Wake up anybody who is waiting on the condemned flag. */ wake_up(&inode->i_wait);}int fs_may_mount(kdev_t dev){ struct inode * inode, * next; int i; next = first_inode; for (i = nr_inodes ; i > 0 ; i--) { inode = next; next = inode->i_next; /* clear_inode() changes the queues.. */ if (inode->i_dev != dev) continue; if (inode->i_count || inode->i_dirt || inode->i_lock) return 0; clear_inode(inode); } return 1;}int fs_may_umount(kdev_t dev, struct inode * mount_root){ struct inode * inode; int i; inode = first_inode; for (i=0 ; i < nr_inodes ; i++, inode = inode->i_next) { if (inode->i_dev != dev || !inode->i_count) continue; if (inode == mount_root && inode->i_count == (inode->i_mount != inode ? 1 : 2)) continue; return 0; } return 1;}int fs_may_remount_ro(kdev_t dev){ struct file * file; int i; /* Check that no files are currently opened for writing. */ for (file = first_file, i=0; i<nr_files; i++, file=file->f_next) { if (!file->f_count || !file->f_inode || file->f_inode->i_dev != dev) continue; if (S_ISREG(file->f_inode->i_mode) && (file->f_mode & 2)) return 0; } return 1;}static void write_inode(struct inode * inode){ if (!inode->i_dirt) return; wait_on_inode(inode); if (!inode->i_dirt) return; if (!inode->i_sb || !inode->i_sb->s_op || !inode->i_sb->s_op->write_inode) { inode->i_dirt = 0; return; } inode->i_lock = 1; inode->i_sb->s_op->write_inode(inode); unlock_inode(inode);}static inline void read_inode(struct inode * inode){ lock_inode(inode); if (inode->i_sb && inode->i_sb->s_op && inode->i_sb->s_op->read_inode) inode->i_sb->s_op->read_inode(inode); unlock_inode(inode);}/* POSIX UID/GID verification for setting inode attributes */int inode_change_ok(struct inode *inode, struct iattr *attr){ /* * If force is set do it anyway. */ if (attr->ia_valid & ATTR_FORCE) return 0; /* Make sure a caller can chown */ if ((attr->ia_valid & ATTR_UID) && (current->fsuid != inode->i_uid || attr->ia_uid != inode->i_uid) && !fsuser()) return -EPERM; /* Make sure caller can chgrp */ if ((attr->ia_valid & ATTR_GID) && (!in_group_p(attr->ia_gid) && attr->ia_gid != inode->i_gid) && !fsuser()) return -EPERM; /* Make sure a caller can chmod */ if (attr->ia_valid & ATTR_MODE) { if ((current->fsuid != inode->i_uid) && !fsuser()) return -EPERM; /* Also check the setgid bit! */ if (!fsuser() && !in_group_p((attr->ia_valid & ATTR_GID) ? attr->ia_gid : inode->i_gid)) attr->ia_mode &= ~S_ISGID; } /* Check for setting the inode time */ if ((attr->ia_valid & ATTR_ATIME_SET) && ((current->fsuid != inode->i_uid) && !fsuser())) return -EPERM; if ((attr->ia_valid & ATTR_MTIME_SET) && ((current->fsuid != inode->i_uid) && !fsuser())) return -EPERM; return 0;}/* * Set the appropriate attributes from an attribute structure into * the inode structure. */void inode_setattr(struct inode *inode, struct iattr *attr){ if (attr->ia_valid & ATTR_UID) inode->i_uid = attr->ia_uid; if (attr->ia_valid & ATTR_GID) inode->i_gid = attr->ia_gid; if (attr->ia_valid & ATTR_SIZE) inode->i_size = attr->ia_size; if (attr->ia_valid & ATTR_ATIME) inode->i_atime = attr->ia_atime; if (attr->ia_valid & ATTR_MTIME) inode->i_mtime = attr->ia_mtime; if (attr->ia_valid & ATTR_CTIME)
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -