Files
Arquivotheca.AIX-4.1.3/bos/kernel/lfs/fio.c
seta75D d6fe8fe829 Init
2021-10-11 22:19:34 -03:00

444 lines
8.5 KiB
C

static char sccsid[] = "@(#)42 1.39.1.10 src/bos/kernel/lfs/fio.c, syslfs, bos411, 9428A410j 5/16/94 13:11:41";
/*
* COMPONENT_NAME: (SYSLFS) Logical File System
*
* FUNCTIONS: getf, getfx, _getf, getft, finit, fpalloc,
* falloc, fpfree, fpgrow, ffree, fp_ufalloc,
* fp_getf, fp_hold
*
* ORIGINS: 3, 26, 27
*
* This module contains IBM CONFIDENTIAL code. -- (IBM
* Confidential Restricted when combined with the aggregated
* modules for this product)
* SOURCE MATERIALS
* (C) COPYRIGHT International Business Machines Corp. 1985, 1993
* All Rights Reserved
*
* US Government Users Restricted Rights - Use, duplication or
* disclosure restricted by GSA ADP Schedule Contract with IBM Corp.
*
*/
#include "sys/param.h"
#include "sys/limits.h"
#include "sys/types.h"
#include "sys/sysmacros.h"
#include "sys/systm.h"
#include "sys/dir.h"
#include "sys/signal.h"
#include "sys/user.h"
#include "sys/errno.h"
#include "sys/filsys.h"
#include "sys/fs_locks.h"
#include "sys/file.h"
#include "sys/conf.h"
#include "sys/inode.h"
#include "sys/var.h"
#include "sys/acct.h"
#include "sys/sysinfo.h"
#include "sys/syspest.h"
#include "sys/lock_alloc.h"
#include "sys/lockname.h"
struct file *ffreelist;
extern nfile_min, nfile_max;
static
int
_getf ( int fd,
struct file ** fpp,
int revokeflag);
static
int
_getf_1thread ( int fd,
struct file ** fpp,
int revokeflag);
static
int
fpgrow ( void);
/*
* Convert a user supplied file descriptor into a pointer
* to a file structure. Kill the process if access to the
* file has been revoked (ie. FREVOKED is set).
*/
int
getf(fd, fpp)
register int fd;
struct file **fpp;
{
if (U.U_procp->p_active == 1)
return _getf_1thread(fd, fpp, 1);
else
return _getf(fd, fpp, 1);
}
/*
* Convert a user supplied file descriptor into a pointer
* to a file structure. It does not verify FREVOKED.
* This is used by close() and exit().
*/
int
getfx(fd, fpp)
register int fd;
struct file **fpp;
{
if (U.U_procp->p_active == 1)
return _getf_1thread(fd, fpp, 0);
else
return _getf(fd, fpp, 0);
}
/* Common handler for getf and getfx -- single-threaded.
* This routine exists to optimize performance in the
* single threaded case. It is a leaf routine, so it
* does not require a stack frame.
*/
static
int
_getf_1thread(
register int fd,
struct file **fpp,
int revokeflag)
{
register struct file *fp;
if (0 <= fd && fd < U.U_maxofile)
{
/* can't be CLOSING because process is single threaded */
if ((fp = U.U_ufd[fd].fp) != NULL)
{
/* fd is now known to be valid */
if ( !((fp->f_flag & FREVOKED) && revokeflag) )
{
*fpp = fp;
U.U_ufd[fd].count++;
return 0;
}
}
}
return EBADF;
}
/* Common handler for getf and getfx. */
static
int
_getf(
register int fd,
struct file **fpp,
int revokeflag)
{
register struct file *fp;
U_FD_LOCK();
if (0 <= fd && fd < U.U_maxofile)
{
if (!(U.U_ufd[fd].flags & UF_CLOSING))
{
if ((fp = U.U_ufd[fd].fp) != NULL)
{
/* fd is now known to be valid */
if ( !((fp->f_flag & FREVOKED) && revokeflag) )
{
*fpp = fp;
U.U_ufd[fd].count++;
U_FD_UNLOCK();
return 0;
}
}
}
}
U_FD_UNLOCK();
return EBADF;
}
/* allocate and return the file pointer for a given file descriptor */
int
fp_getf(fd, fpp)
int fd; /* file descriptor of file pointer */
struct file **fpp; /* file pointer return address */
{
if (U.U_procp->p_active == 1)
return _getf_1thread(fd, fpp, 1);
else
return _getf(fd, fpp, 1);
}
/*
* getft - Get the file pointer referred to by a file descriptor and
* validate the type.
*/
int
getft(fd, fpp, want)
int fd;
struct file **fpp;
int want;
{
int rc;
struct file *fp;
if (U.U_procp->p_active == 1)
rc = _getf_1thread(fd, &fp, 1);
else
rc = _getf(fd, &fp, 1);
if (rc == 0)
if (fp->f_type != want)
{
ufdrele(fd);
rc = EINVAL;
}
else
*fpp = fp;
return rc;
}
void
finit()
{
register struct file *fp;
/* Initialize the file free list lock */
lock_alloc(&ffree_lock,LOCK_ALLOC_PAGED,FFREE_LOCK_CLASS,-1);
simple_lock_init(&ffree_lock);
v.v_file = 0;
v.ve_file = (caddr_t) &file[0];
fpgrow();
U.U_cmask = CMASK; /* file creation mask */
U.U_maxofile = 0; /* initialize max open files */
U.U_compatibility = PROC_RAWDIR; /* default to raw directories */
}
/*
* fpalloc Allocate a file table entry. Return 0 if success,
* else return the error number. The allocated file
* pointer is returned via fpp.
*/
int
fpalloc(vp, flag, type, ops, fpp)
struct vnode * vp; /* pointer to associated vnode */
int flag; /* new value for f_flag field */
int type; /* type of file struct */
struct fileops * ops; /* pointer to file op structure */
struct file ** fpp; /* pointer to rtn'd file pointer*/
{
register struct file *fp;
FFREE_LOCK();
while ((fp = ffreelist) == NULL)
if (!fpgrow())
{
FFREE_UNLOCK();
return ENFILE; /* exhausted system open file table */
}
ffreelist = fp->f_next;
FFREE_UNLOCK();
ASSERT(fp->f_count == 0);
fp->f_count = 1;
fp->f_vnode = vp;
fp->f_flag = flag;
fp->f_type = type;
fp->f_ops = ops;
fp->f_offset = 0;
fp->f_dir_off = 0;
fp->f_cred = NULL;
fp->f_vinfo = NULL;
*fpp = fp;
return 0;
}
fpfree(fp)
struct file *fp;
{
ASSERT(fp->f_count == 0);
FFREE_LOCK();
fp->f_next = ffreelist;
ffreelist = fp;
FFREE_UNLOCK();
}
/*
* NAME: fp_ufalloc
*
* FUNCTION: copy a file table entry. Allocate
* a user file descriptor that refers to
* the new file pointer. This is used by ptrace.
* New file table entry is seeked to zero and has
* FEXEC turned off.
*
* RETURNS: newly allocated file descriptor OR
* -1 with u_error set if an error occurred.
*/
int
fp_ufalloc(fp)
register struct file *fp;
{
int newfd = 0;
struct file *newfp = NULL;
short flag;
int rc;
int klock;
/* Note: this routine assumes that the fp that is passed in
* is held and cannot be freed while this routine is executing.
*/
if ((klock = IS_LOCKED(&kernel_lock)) != 0)
unlockl(&kernel_lock);
ASSERT(fp != NULL);
ASSERT(fp->f_count > 0);
ASSERT(fp->f_type == DTYPE_VNODE);
if (rc = ufdalloc(0, &newfd))
goto out;
/* if FEXEC is on we turn it off and turn on FREAD */
flag = fp->f_flag;
if (flag & FEXEC)
{
flag |= FREAD;
flag &= ~FEXEC;
}
if (rc = fpalloc(fp->f_vnode, flag, fp->f_type, fp->f_ops, &newfp))
goto out;
rc = VNOP_OPEN(fp->f_vnode, flag, NULL, &(newfp->f_vinfo), fp->f_cred);
out:
if (!rc)
{
/* newfp->f_vnode is the same as fp->f_vnode */
VNOP_HOLD(newfp->f_vnode);
/* hold the cred struct and fill in the cred pointer */
crhold(fp->f_cred);
newfp->f_cred = fp->f_cred;
/*
* Don't need to take the u_fd_lock for the following
* assignment since no one can use this file pointer
*/
U.U_ufd[newfd].fp = newfp;
}
else
{
if (newfd)
ufdfree(newfd);
if (newfp)
{
newfp->f_count = 0;
fpfree(newfp);
}
}
if (klock)
lockl(&kernel_lock, LOCK_SHORT);
return (rc ? -1 : newfd);
}
void
fp_hold(fp)
struct file *fp;
{
ASSERT(fp != NULL);
ASSERT(fp->f_count > 0);
FP_LOCK(fp);
fp->f_count++;
FP_UNLOCK(fp);
return;
}
/*
* fpgrow - grow the system open file table by a page. Return TRUE
* if the growth was successful, else return FALSE.
*/
static
int
fpgrow(void)
{
struct file *fp;
int i;
int grow;
static int slotno = 1;
/* ffree_lock must be held on entry to this routine */
/*
* check for full file table
* return
*/
if (v.v_file >= nfile_max)
return 0;
/*
* Try to grow the file table to the next page boundary.
* If there is not room to grow by a full page then calculate
* the growth to fill the file table.
*/
fp = ((int)v.ve_file + PAGESIZE) & ~(PAGESIZE-1);
grow = (int)((char *)fp - v.ve_file) / sizeof(struct file);
if (grow <= 1)
grow += PAGESIZE / sizeof(struct file);
if (v.v_file + grow > nfile_max)
{
grow = nfile_max - v.v_file;
if (grow == 0)
return 0;
}
/*
* link the newly allocated files
*/
fp = (struct file *)v.ve_file;
for (i = 0; i < grow; i++)
{
fp[i].f_next = &fp[i+1];
lock_alloc(&fp[i].f_lock,
LOCK_ALLOC_PAGED, FPTR_LOCK_CLASS, slotno);
simple_lock_init(&fp[i].f_lock);
lock_alloc(&fp[i].f_offset_lock,
LOCK_ALLOC_PAGED, FOFF_LOCK_CLASS, slotno);
simple_lock_init(&fp[i].f_offset_lock);
slotno++;
}
fp[grow-1].f_next = NULL;
v.v_file += grow;
v.ve_file = (caddr_t) &fp[grow];
ffreelist = fp;
return 1;
}
/*
* free a file table entry
*/
void
ffree(fp)
struct file *fp;
{
/*
* Don't need a lock for this assignment since I am
* simply zero'ing the value out.
*/
fp->f_count = 0;
fpfree(fp);
}