📄 gfs_gnodeops.c
字号:
goto done; } } if (mode == GFBLK) { /* * On last close of a block device (that isn't mounted) * we must invalidate any in core blocks, so that * we can, for instance, change floppy disks. */ GETMP(mp, dev); /* * If GETMP returns a mp, then the block device * is mounted on, so return. */ if (mp != NULL) { /* * Decrement ref count in gnode */ grele(gp); goto done; } bflush(dev, (struct gnode *) 0, 0); binval(dev, (struct gnode *) 0); } if (setjmp(&u.u_qsave)) { /* * If device close routine is interrupted, * must return so closef can clean up. */ if (u.u_error == 0) u.u_error = EINTR; /* ??? */ goto done; } } if (GCLOSE(gp, flag) == GNOFUNC) u.u_error = EOPNOTSUPP; if (mode == GFBLK || mode == GFCHR) divorce_dev(gp->g_rdev, mode); gfs_lock(gp); gput(gp);done: return(u.u_error);}/* * Place an advisory lock on an inode. */gno_lock(fp, cmd) register struct file *fp; register int cmd;{ register int priority = PLOCK; register struct gnode *gp = (struct gnode *)fp->f_data; if ((cmd & LOCK_EX) == 0) priority++; if (setjmp(&u.u_qsave)) { if ((u.u_sigintr & sigmask(u.u_procp->p_cursig)) != 0) return(EINTR); u.u_eosys = RESTARTSYS; return (0); } /* * If there's a exclusive lock currently applied * to the file, then we've gotta wait for the * lock with everyone else. */again: /* SMP lock gnode during locking operation */ gfs_lock(gp); while (gp->g_flag & GEXLOCK) { /* * If we're holding an exclusive * lock, then release it. */ if (fp->f_flag & FEXLOCK) { gno_unlock(fp, FEXLOCK); continue; } if (cmd & LOCK_NB) { gfs_unlock(gp); return (EWOULDBLOCK); } gp->g_flag |= GLWAIT; sleep_unlock((caddr_t)&gp->g_exlockc, priority, &gp->g_lk); gfs_lock(gp); } if (cmd & LOCK_EX && (gp->g_flag & GSHLOCK)) { /* * Must wait for any shared locks to finish * before we try to apply a exclusive lock. * * If we're holding a shared * lock, then release it. */ if (fp->f_flag & FSHLOCK) { gno_unlock(fp, FSHLOCK); gfs_unlock(gp); goto again; } if (cmd & LOCK_NB) { gfs_unlock(gp); return (EWOULDBLOCK); } gp->g_flag |= GLWAIT; sleep_unlock((caddr_t)&gp->g_shlockc, PLOCK, &gp->g_lk); goto again; } if (fp->f_flag & FEXLOCK) panic("gno_lock"); if (cmd & LOCK_EX) { cmd &= ~LOCK_SH; gp->g_exlockc++; gp->g_flag |= GEXLOCK; fp->f_flag |= FEXLOCK; } if ((cmd & LOCK_SH) && (fp->f_flag & FSHLOCK) == 0) { gp->g_shlockc++; gp->g_flag |= GSHLOCK; fp->f_flag |= FSHLOCK; } gfs_unlock(gp); return (0);}/* * Unlock a file. */gno_unlock(fp, kind) register struct file *fp; register int kind;{ register struct gnode *gp = (struct gnode *)fp->f_data; register int flags; register int unlck = 0; kind &= fp->f_flag; if (gp == NULL || kind == 0) return; /* Will be true when gno_unlock is called from flock() */ if (!smp_owner(&gp->g_lk)) { unlck = 1; gfs_lock(gp); } flags = gp->g_flag; if (kind & FSHLOCK) { if ((flags & GSHLOCK) == 0) panic("gno_unlock: SHLOCK"); if (--gp->g_shlockc == 0) { gp->g_flag &= ~GSHLOCK; if (flags & GLWAIT) wakeup((caddr_t)&gp->g_shlockc); } fp->f_flag &= ~FSHLOCK; } if (kind & FEXLOCK) { if ((flags & GEXLOCK) == 0) panic("gno_unlock: EXLOCK"); if (--gp->g_exlockc == 0) { gp->g_flag &= ~(GEXLOCK|GLWAIT); if (flags & GLWAIT) wakeup((caddr_t)&gp->g_exlockc); } fp->f_flag &= ~FEXLOCK; } if (unlck) gfs_unlock(gp);}/* * Revoke access the current tty by all processes. * Used only by the super-user in init * to give ``clean'' terminals at login. */vhangup(){ struct tty *tp; if (!suser()) return; if ((tp = u.u_procp->p_ttyp) == NULL) return; forceclose(u.u_ttyd); if ((tp->t_state) & TS_ISOPEN) gsignal(tp->t_pgrp, SIGHUP);}/* * vhangup() is called when a terminal line is to be cleared of any * references by any other process when a login is attempted. This * handles the case where a terminal line is open and a login occured * on the same line, any write (or read or select or....) will be * handled by the divorceops. */#define D_TO_TTY(dev) \ (cdevsw[major((dev))].d_ttys \ ? (struct tty *)&cdevsw[major(dev)].d_ttys[minor(dev)] \ : (struct tty *)0)forceclose(dev) dev_t dev;{ struct tty *tp = D_TO_TTY(dev); int saveaffinity; int flag; if (flag = divorce_dev(dev, GFCHR)) { CALL_TO_NONSMP_DRIVER(cdevsw[major(dev)], saveaffinity); (*cdevsw[major(dev)].d_close) (dev, flag); RETURN_FROM_NONSMP_DRIVER(cdevsw[major(dev)], saveaffinity); } /* * zap ctltty so /dev/tty connection is broken */ if (tp) { FORALLPROC( if (pp->p_ttyp == tp && proc_get(pp->p_pid) == pp) { if (pp->p_ttyp == tp) /* change during proc_get? */ pp->p_ttyp = (struct tty *)0; proc_rele(pp); } ) } /* * Since a call to the drivers close routine can take a real * long time, lets do it again for any file table enties that * were being opened while we were blocked closing the device. */ divorce_dev(dev, GFCHR);}/* * divorce_dev() will walk through the file table. setting the file ops * vector array to divorce_ops. Any further requests with the file * descriptor will result in an error. When the file descriptor is closed, * the gnode reference count will be decremented as always. */divorce_dev(dev, mode) dev_t dev; int mode;{ register struct file *fp; register struct gnode *gp; register caddr_t value; int flag = 0;top: /* * We hold the file table througout the search because * f_data is now protected with it (if f_type == DTYPE_INODE). */ smp_lock(&lk_file, LK_RETRY); for (fp = file; fp < fileNFILE; fp++) { if (fp->f_count == 0) continue; if (fp->f_type != DTYPE_INODE) continue; if (fp->f_ops == &divorceops) continue; gp = (struct gnode *)fp->f_data; if (gp == 0) continue; if ((gp->g_mode & GFMT) != mode) continue; if (gp->g_rdev != dev) continue; if (gp->g_flag & GINUSE) { smp_unlock(&lk_file); (*fp->f_ops->fo_ioctl)(fp, FIOCINUSE, value, fp->f_cred); wakeup((caddr_t)&gp->g_flag); gfs_lock(gp); gp->g_flag &= ~(GINUSE); gfs_unlock(gp); goto top; } fp->f_ops = &divorceops; flag = fp->f_flag; } smp_unlock(&lk_file); return(flag);}divorce_rw(fp, rw, uio) register struct file *fp; register enum uio_rw rw; register struct uio *uio;{ return(EBADF);}divorce_ioctl(fp, com, data) register struct file *fp; register int com; register caddr_t data;{ return(EBADF);}divorce_select(fp, which) register struct file *fp; register int which;{ return(EBADF);}divorce_close(fp) register struct file *fp;{ register struct gnode *gp = (struct gnode *)fp->f_data; /* * We don't have to hold the file table lock here, * because nobody cares about file table entries with * divorceops. */ gfs_lock(gp); gput(gp); return(0);}/* * Remove a gnode from the gnode cache (make the gnode active ) */voidgremque(gp) register struct gnode *gp;{ register struct gnode *gq; gq = gp->g_freef; *(gp->g_freeb) = gq; if (gq) gq->g_freeb = gp->g_freeb; else gfreet = gp->g_freeb; gp->g_freef = NULL; gp->g_freeb = NULL;}/* * This routine is called for every file close (excluding kernel processes * that call closef() directly) in order to implement the * SVID 'feature' that the FIRST close of a descriptor that refers to * a locked object causes all the locks to be released for that object. * It is called, for example, by close(), exit(), exec(), & dup2(). * * NOTE: If the SVID ever changes to hold locks until the LAST close, * then this routine might be moved to closef(). * */intgno_lockrelease(fp) register struct file *fp;{ /* * Only do extra work if the process has done record-locking. */ if (u.u_procp->p_file & SLKDONE) { register struct gnode *gp; register struct file *ufp; register int i; register int locked; struct flock ld; locked = 0; u.u_procp->p_file &= ~SLKDONE; /* reset process flag */ gp = (struct gnode *)fp->f_data; /* * Check all open files to see if there's a lock * possibly held for this gnode. */ for (i = u.u_omax; i-- > 0; ) { if (((ufp = U_OFILE(i)) != NULL) && (U_POFILE(i) & UF_FDLOCK)) { /* the current file has an active lock */ if ((struct gnode *)ufp->f_data == gp) { /* release this lock */ locked = 1; /* (later) */ U_POFILE_SET(i, U_POFILE(i) & ~UF_FDLOCK); } else { /* another file is locked */ u.u_procp->p_file |= SLKDONE; } } } /* for all files */ /* * If 'locked' is set, release any locks that this process * is holding on this file. If record-locking on any other * files was detected, the process was marked (SLKDONE) to * run thru this loop again at the next file close. */ if (locked) { ld.l_type = F_UNLCK; /* set to unlock entire file */ ld.l_whence = 0; /* unlock from start of file */ ld.l_start = 0; ld.l_len = 0; /* do entire file */ return (GRLOCK(gp, &ld, F_SETLK, fp)); } } return (0);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -