ufs_inode.c
来自「操作系统SunOS 4.1.3版本的源码」· C语言 代码 · 共 439 行
C
439 行
#ifndef lintstatic char sccsid[] = "@(#)ufs_inode.c 1.1 92/07/30 Copyr 1986 Sun Micro";#endif/* * Copyright (c) 1986 by Sun Microsystems, Inc. */#include <sys/param.h>#include "boot/systm.h"#include <sys/user.h>#include <sys/vfs.h>#include "boot/vnode.h"#include <sys/buf.h>#include <sys/kernel.h>#include "boot/cmap.h"#include <ufs/mount.h>#include "boot/inode.h"#include <ufs/fs.h>#ifdef QUOTA#include <ufs/quota.h>#endif#ifdef NFS_BOOT#undef uextern struct user u;/* * Small hash list for /boot. */#define INOHSZ 1/* * Small inode list also. Note: the kernel one is set up * by config; we just set ours up statically. */#define NINODES 10struct inode inodes[NINODES];struct inode *inode = &inodes[0];struct inode *inodeNINODE = &inodes[NINODES-1];int ninode = NINODES;#else #define INOHSZ 64#endif /* NFS_BOOT */#define INOHASH(dev,ino) (((unsigned)((dev)+(ino)))%INOHSZ)union ihead { /* inode LRU cache, Chris Maltby */ union ihead *ih_head[2]; struct inode *ih_chain[2];} ihead[INOHSZ];struct inode *ifreeh, **ifreet;/* * Convert inode formats to vnode types */enum vtype iftovt_tab[] = { VFIFO, VCHR, VDIR, VBLK, VREG, VLNK, VSOCK, VBAD};int vttoif_tab[] = { 0, IFREG, IFDIR, IFBLK, IFCHR, IFLNK, IFSOCK, IFMT, IFIFO};/* * Initialize hash links for inodes * and build inode free list. */ihinit(){ register int i; register struct inode *ip = inode; register union ihead *ih = ihead; for (i = INOHSZ; --i >= 0; ih++) { ih->ih_head[0] = ih; ih->ih_head[1] = ih; } ifreeh = ip; ifreet = &ip->i_freef; ip->i_freeb = &ifreeh; ip->i_forw = ip; ip->i_back = ip; ip->i_vnode.v_data = (caddr_t)ip; ip->i_vnode.v_op = &ufs_vnodeops; for (i = ninode; --i > 0; ) { ++ip; ip->i_forw = ip; ip->i_back = ip; *ifreet = ip; ip->i_freeb = ifreet; ifreet = &ip->i_freef; ip->i_vnode.v_data = (caddr_t)ip; ip->i_vnode.v_op = &ufs_vnodeops; } ip->i_freef = NULL;}/* * Look up an inode by device,inumber. * If it is in core (in the inode structure), * honor the locking protocol. * If it is not in core, read it in from the * specified device. * If the inode is mounted on, perform * the indicated indirection. * In all cases, a pointer to a locked * inode structure is returned. * * panic: no imt -- if the mounted file * system is not in the mount table. * "cannot happen" */struct inode *iget(dev, fs, ino) dev_t dev; register struct fs *fs; ino_t ino;{ register struct inode *ip; register union ihead *ih; register struct buf *bp; register struct dinode *dp; register struct inode *iq; register struct vnode *vp; struct mount *mp; /* * lookup inode in cache */loop: mp = getmp(dev); if (mp == NULL) { panic("iget: bad dev\n"); } if (mp->m_bufp->b_un.b_fs != fs) panic("iget: bad fs"); ih = &ihead[INOHASH(dev, ino)]; for (ip = ih->ih_chain[0]; ip != (struct inode *)ih; ip = ip->i_forw) if (ino == ip->i_number && dev == ip->i_dev) { /* * found it. check for locks */ if ((ip->i_flag & ILOCKED) != 0) { ip->i_flag |= IWANT; (void) sleep((caddr_t)ip, PINOD); goto loop; } /* * If inode is on free list, remove it. */ if ((ip->i_flag & IREF) == 0) { if (iq = ip->i_freef) iq->i_freeb = ip->i_freeb; else ifreet = ip->i_freeb; *ip->i_freeb = iq; ip->i_freef = NULL; ip->i_freeb = NULL; } /* * mark inode locked and referenced and return it. */ ip->i_flag |= ILOCKED | IREF; VN_HOLD(ITOV(ip)); return(ip); } /* * Inode was not in cache. Get free inode slot for new inode. */ while (ifreeh == NULL) { } if ((ip = ifreeh) == NULL) { tablefull("inode"); u.u_error = ENFILE; return(NULL); } if (iq = ip->i_freef) iq->i_freeb = &ifreeh; ifreeh = iq; ip->i_freef = NULL; ip->i_freeb = NULL; /* * Now to take inode off the hash chain it was on * (initially, or after an iflush, it is on a "hash chain" * consisting entirely of itself, and pointed to by no-one, * but that doesn't matter), and put it on the chain for * its new (ino, dev) pair */ remque(ip); insque(ip, ih);#ifdef QUOTA dqrele(ip->i_dquot); ip->i_dquot = NULL;#endif ip->i_flag = ILOCKED | IREF; ip->i_dev = dev; ip->i_devvp = mp->m_devvp; ip->i_number = ino; ip->i_diroff = 0; ip->i_fs = fs; ip->i_lastr = 0; bp = bread(ip->i_devvp, (daddr_t)fsbtodb(fs, itod(fs, ino)), (int)fs->fs_bsize); /* * Check I/O errors */ if ((bp->b_flags & B_ERROR) != 0) { brelse(bp); /* * the inode doesn't contain anything useful, so it would * be misleading to leave it on its hash chain. * 'iput' will take care of putting it back on the free list. */ remque(ip); ip->i_forw = ip; ip->i_back = ip; /* * we also loose its inumber, just in case (as iput * doesn't do that any more) - but as it isn't on its * hash chain, I doubt if this is really necessary .. kre * (probably the two methods are interchangable) */ ip->i_number = 0; iunlock(ip); iinactive(ip); return(NULL); } dp = bp->b_un.b_dino; dp += itoo(fs, ino); ip->i_ic = dp->di_ic; vp = ITOV(ip); VN_INIT(vp, mp->m_vfsp, IFTOVT(ip->i_mode), ip->i_rdev); if (ino == (ino_t)ROOTINO) { vp->v_flag |= VROOT; } brelse(bp);#ifdef QUOTA if (ip->i_mode != 0) ip->i_dquot = getinoquota(ip);#endif return (ip);}/* * Vnode is no loger referenced, write the inode out and if necessary, * truncate and deallocate the file. */iinactive(ip) register struct inode *ip;{ if (ip->i_flag & ILOCKED) panic("ufs_inactive"); if (ip->i_fs->fs_ronly == 0) {#ifdef NFS_BOOT /* * When booting all inodes are read only. */#else ip->i_flag |= ILOCKED; if (ip->i_nlink <= 0) { ip->i_gen++; itrunc(ip, (u_long)0); mode = ip->i_mode; ip->i_mode = 0; ip->i_rdev = 0; imark(ip, IUPD|ICHG); ifree(ip, ip->i_number, mode);#ifdef QUOTA (void)chkiq(VFSTOM(ip->i_vnode.v_vfsp), ip, ip->i_uid, 0); dqrele(ip->i_dquot); ip->i_dquot = NULL;#endif } if (ip->i_flag & (IUPD|IACC|ICHG)) iupdat(ip, 0); iunlock(ip);#endif /* NFS_BOOT */ } ip->i_flag = 0; /* * Put the inode on the end of the free list. * Possibly in some cases it would be better to * put the inode at the head of the free list, * (eg: where i_mode == 0 || i_number == 0) * but I will think about that later .. kre * (i_number is rarely 0 - only after an i/o error in iget, * where i_mode == 0, the inode will probably be wanted * again soon for an ialloc, so possibly we should keep it) */ if (ifreeh) { *ifreet = ip; ip->i_freeb = ifreet; } else { ifreeh = ip; ip->i_freeb = &ifreeh; } ip->i_freef = NULL; ifreet = &ip->i_freef;}/* * Mark the accessed, updated, or changed times in an inode * with the current (unique) time */imark(ip, flag) register struct inode *ip; register int flag;{ struct timeval ut;#ifdef NFS_BOOT ut.tv_sec = 0; ut.tv_usec = 0;#else uniqtime(&ut);#endif /* NFS_BOOT */ ip->i_flag |= flag; if (flag & IACC) ip->i_atime = ut; if (flag & IUPD) ip->i_mtime = ut; if (flag & ICHG) { ip->i_diroff = 0; ip->i_ctime = ut; }}/* * Lock an inode. If its already locked, set the WANT bit and sleep. */ilock(ip) register struct inode *ip;{ ILOCK(ip);}/* * Unlock an inode. If WANT bit is on, wakeup. */iunlock(ip) register struct inode *ip;{ if (!(ip->i_flag & ILOCKED)) { panic("iunlock"); } IUNLOCK(ip);}/* * Check mode permission on inode. * Mode is READ, WRITE or EXEC. * In the case of WRITE, the * read-only status of the file * system is checked. * Also in WRITE, prototype text * segments cannot be written. * The mode is shifted to select * the owner/group/other fields. * The super user is granted all * permissions. */iaccess(ip, m) register struct inode *ip; register int m;{ register int *gp; if (m & IWRITE) { register struct vnode *vp; vp = ITOV(ip); /* * Disallow write attempts on read-only * file systems; unless the file is a block * or character device resident on the * file system. */ if (ip->i_fs->fs_ronly != 0) { if ((ip->i_mode & IFMT) != IFCHR && (ip->i_mode & IFMT) != IFBLK) { u.u_error = EROFS; return (EROFS); } } /* * If there's shared text associated with * the inode, try to free it up once. If * we fail, we can't allow writing. */ if (vp->v_flag & VTEXT) xrele(vp); if (vp->v_flag & VTEXT) { u.u_error = ETXTBSY; return (ETXTBSY); } } /* * If you're the super-user, * you always get access. */ if (u.u_uid == 0) return (0); /* * Access check is based on only * one of owner, group, public. * If not owner, then check group. * If not a member of the group, then * check public access. */ if (u.u_uid != ip->i_uid) { m >>= 3; if (u.u_gid == ip->i_gid) goto found; gp = u.u_groups; for (; gp < &u.u_groups[NGROUPS] && *gp != NOGROUP; gp++) if (ip->i_gid == *gp) goto found; m >>= 3; }found: if ((ip->i_mode & m) == m) return (0); u.u_error = EACCES; return (EACCES);}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?