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

417 lines
10 KiB
C

static char sccsid[] = "@(#)55 1.25.1.10 src/bos/kernel/lfs/mount.c, syslfs, bos411, 9430C411a 7/26/94 12:56:31";
/*
* COMPONENT_NAME: (SYSLFS) Logical File System
*
* FUNCTIONS: vmount, smount, vmountdata, vfslock, vfsunlock
*
* ORIGINS: 3, 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, 1994
* 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/types.h"
#include "sys/systm.h"
#include "sys/pri.h"
#include "string.h"
#include "sys/user.h"
#include "sys/vfs.h"
#include "sys/fs_locks.h"
#include "sys/errno.h"
#include "sys/access.h"
#include "sys/pathname.h"
#include "sys/gpai.h"
#include "sys/syspest.h"
#include "sys/malloc.h"
#include "sys/var.h"
#include "sys/priv.h"
#include "sys/audit.h"
#define MAXVMTSIZE (MAXPATH * (VMT_LASTINDEX+1))
#define ROUNDUP(x) (((x) + 3) & ~3)
BUGVDEF(mdebug, 0); /* define debug variable */
extern struct galloc gpa_vfs;
extern struct gfs *gfsindex[]; /* AIX virtual file systems */
extern int max_gfstype;
/************************************************************************
*
* NAME: vmount system call
*
* FUNCTION: The new AIX mount for mounting of local devices or
* local or remote directories over local directories.
* Also mounts local or remote files over local files.
*
* PARAMETERS: vmountp - pointer to a vmount structure filled in
* by a mount helper or the mount command.
* vlength - length of the (variable sized) vmount structure.
*
* RETURNS: zero on success, -1 on error. Also the requested
* mount operation is performed.
*
************************************************************************/
vmount(uapvmountp, vlength)
struct vmount *uapvmountp; /* vmount structure pointer */
int vlength; /* length of vmount struct */
{
extern kernel_lock; /* global kernel lock */
static int svcnum = 0;
struct vmount *vmountp = NULL;
struct vmt_data *vdp;
struct vmt_data *endvdp;
int error = 0;
int lockt, /* previous state of kernel lock */
svcrc = 0,
size,
offset,
vfstype;
/* Grab the global kernel lock */
lockt = FS_KLOCK(&kernel_lock, LOCK_SHORT);
if (audit_flag)
svcrc = audit_svcstart("FS_Mount",&svcnum,0);
BUGLPR(mdebug, BUGNFO, ("Vmount entry: ptr=0x%x, len=%d\n",
uapvmountp, vlength));
/*
* This is a sanity check: malloc panics, if it gets too
* big a number.
*/
if (vlength < sizeof(struct vmount) || vlength > MAXVMTSIZE) {
BUGLPR(mdebug, BUGACT, ("Bad vmount length\n"));
goto einval;
}
if ((vmountp = (struct vmount *)malloc(vlength)) == NULL) {
BUGLPR(mdebug, BUGACT, ("Malloc error in vmount\n"));
error = ENOMEM;
goto out;
}
if (copyin(uapvmountp, vmountp, vlength)) {
error = EFAULT;
goto out;
}
/*
* Verify that the system call was correctly invoked.
*/
if (vmountp->vmt_length != vlength ||
vmountp->vmt_revision != VMT_REVISION) {
goto einval;
}
/*
* Verify that the memory areas described by the
* offset and size fields in the vmount are within
* the memory:
* [vmountp, vmountp + vlength)
* and check that the fields are not overlapping.
* The checks are done assuming that the fields will
* be assigned such that:
* fields of size 0 have offset zero
* fileds are integer aligned
* vmountp->vmt_data[i].vmt_off < vmountp->vmt_data[j].vmt_off
* (for i < j)
* there is no U.Used memory at the end of the structure
*/
vdp = vmountp->vmt_data;
endvdp = vdp + VMT_LASTINDEX;
offset = ROUNDUP (sizeof (struct vmount));
for (; vdp <= endvdp; vdp++) {
size = vdp->vmt_size;
if (size < 0)
goto einval;
if (size == 0) {
vdp->vmt_off = 0;
continue;
}
if (vdp->vmt_off != offset)
goto einval;
offset += ROUNDUP (size);
if (offset >= vlength && vdp != endvdp)
goto einval;
}
if (offset != vlength)
goto einval;
/*
* The VMT_STUB and VMT_OBJECT fields should be null
* terminated strings. The other fields are file system
* specific and should be validated by the file system
* implementation.
*/
if (! memchr (vmt2dataptr (vmountp, VMT_STUB), '\0',
vmt2datasize (vmountp, VMT_STUB)) ||
! memchr (vmt2dataptr (vmountp, VMT_OBJECT), '\0',
vmt2datasize (vmountp, VMT_OBJECT))) {
einval: error = EINVAL;
goto out;
}
if(svcrc) {
if (vmt2dataptr(vmountp, VMT_OBJECT))
audit_svcbcopy(vmt2dataptr(vmountp, VMT_OBJECT),
strlen(vmt2dataptr(vmountp, VMT_OBJECT)) + 1);
if (vmt2dataptr(vmountp, VMT_STUB))
audit_svcbcopy(vmt2dataptr(vmountp, VMT_STUB),
strlen(vmt2dataptr(vmountp, VMT_STUB)) + 1);
}
/*
* restrict input flags to those that user of vmount() may set.
*/
vmountp->vmt_flags &= VMOUNT_MASK;
/*
* Make sure there is a gfs for this type
* and put a hold on it so it can't go away.
*/
vfstype = vmountp->vmt_gfstype;
GFS_LOCK();
if (vfstype < 0 || vfstype > max_gfstype || gfsindex[vfstype] == NULL)
error = ENOSYS;
else
gfsindex[vfstype]->gfs_hold++;
GFS_UNLOCK();
if (error)
goto out;
error = smount(vmountp);
if (error)
{
GFS_LOCK();
gfsindex[vfstype]->gfs_hold--;
GFS_UNLOCK();
}
out:
if(svcrc)
audit_svcfinis();
if (error && vmountp != NULL)
free(vmountp);
/* Unlock the kernel lock unless nested locks occurred */
if( lockt != LOCK_NEST )
FS_KUNLOCK(&kernel_lock);
if (error)
u.u_error = error;
return error ? -1 : 0;
}
/*
* smount -- Common code for all varieties of mount system call.
*/
int
smount(vmountp)
struct vmount *vmountp;
{
int error;
register struct vfs *vfsp, *tmp;
extern struct vfs *rootvfs;
struct vnode *stubvp = NULL;
int vfstype = vmountp->vmt_gfstype;
struct ucred *crp;
static vfsnumber = 1; /* stamps a unique number on each vfs */
BUGLPR(mdebug, BUGACT,
("Smount entry: type=%d, ptr=0x%x, len=%d bytes\n",
vfstype, vmountp, vmountp->vmt_length));
/* Get creds for the VFS and vnode operations */
crp = crref();
/*
* Allocate and initialize new vfs struct.
*/
if ((vfsp = (struct vfs *) gpai_alloc(&gpa_vfs)) == NULL)
{
error = ENOMEM;
goto outstub;
}
/* Initialize vfs structure */
vfsp->vfs_mdata = vmountp;
vfsp->vfs_gfs = gfsindex[vfstype];
vfsp->vfs_date = time;
vmountp->vmt_vfsnumber = fetch_and_add(&vfsnumber, 1);
vfsp->vfs_number = vmountp->vmt_vfsnumber;
vfsp->vfs_vnodes = NULL;
vfsp->vfs_data = NULL;
vfsp->vfs_count = 1;
vfsp->vfs_bsize = 0;
vfsp->vfs_rsvd1 = 0;
vfsp->vfs_rsvd2 = 0;
try_again:
/*
* Find the stub to be mounted upon.
*/
error = lookupname(vmt2dataptr(vmountp, VMT_STUB),
SYS, L_SEARCH, NULL, &stubvp, crp);
if (stubvp == NULL)
{
BUGLPR(mdebug, BUGACT, ("stubvp = NULL, error %d\n", error));
goto outstub;
}
/* set stub in the vfs */
vfsp->vfs_mntdover = stubvp;
/* write permission on stub is only permission required */
/* to allow mounting of the object over the stub. */
/* VNOP_ACCESS returns error, therefore FALSE (0) means OK */
if (!VNOP_ACCESS(stubvp, W_ACC, NULL, crp))
vfsp->vfs_flag |= VFS_VMOUNTOK; /* kludge to inform vfs_mount()
routines of stub permissions;
cleared at smount exit. */
if (priv_req(FS_CONFIG))
vfsp->vfs_flag |= VFS_SUSER;
/*
* Lock the stub vnode to prevent multiple simultaneous
* mounts over the same point -- which would result in
* unreachable file systems.
*/
VN_LOCK(stubvp);
if (stubvp->v_mvfsp)
{
VN_UNLOCK(stubvp);
VNOP_RELE(stubvp);
goto try_again;
}
/* Restrict mount ala System V for SVVS */
if (vmountp->vmt_flags & VFS_SYSV_MOUNT)
{
if (stubvp->v_flag & V_ROOT || stubvp->v_count > 1)
{
error = EBUSY;
goto outstub;
}
vmountp->vmt_flags &= ~VFS_SYSV_MOUNT;
}
/*
* Switch to file system dependent code.
*/
BUGLPR(mdebug, BUGACT, ("Switching to vfs_mount...\n"));
BUGLPR(mdebug, BUGACT, (" object: \"%s\", vfsp 0x%x\n",
vmt2dataptr(vfsp->vfs_mdata, VMT_OBJECT), vfsp));
error = VFS_MOUNT(vfsp, crp);
if (error)
goto outstub;
/*
* initialization of the vfs is complete.
* point the stub vnode at the new vfs and
* link the new vfs into the list of file systems.
*/
stubvp->v_mvfsp = vfsp;
VN_UNLOCK(stubvp);
vfsp->vfs_flag &= ~(VFS_VMOUNTOK|VFS_SUSER);
VFS_LIST_LOCK();
for (tmp = rootvfs; tmp->vfs_next != NULL; tmp = tmp->vfs_next)
/* null */;
tmp->vfs_next = vfsp;
vfsp->vfs_next = NULL;
VFS_LIST_UNLOCK();
crfree(crp);
return(0);
outstub:
if (stubvp)
{
VN_UNLOCK(stubvp);
VNOP_RELE(stubvp);
}
if (vfsp)
{
gpai_free(&gpa_vfs, vfsp);
}
crfree(crp);
return(error);
}
/*
* vmountdata - stuffs it's arguments into the vmount
* structure pointed at by vmtp. Only used by jfs_rootinit,
* who has to hand-build a vmount structure.
*/
vmountdata(vmtp, obj, stub, host, name, info, args)
register struct vmount *vmtp;
char *obj, *stub, *host, *name, *info, *args;
{
register struct vmt_data *vdp, *vdprev;
register int size;
BUGLPR(mdebug, BUGACT,
("Entry to vmountdata 0x%x %s %s %s %s %s %s\n",
vmtp, obj, stub, host, name, info, args));
vdp = vmtp->vmt_data;
vdp->vmt_off = sizeof(struct vmount);
size = ROUNDUP(strlen(obj) + 1);
vdp->vmt_size = size;
strcpy(vmt2dataptr(vmtp, VMT_OBJECT), obj);
vdprev = vdp;
vdp++;
vdp->vmt_off = vdprev->vmt_off + size;
size = ROUNDUP(strlen(stub) + 1);
vdp->vmt_size = size;
strcpy(vmt2dataptr(vmtp, VMT_STUB), stub);
vdprev = vdp;
vdp++;
vdp->vmt_off = vdprev->vmt_off + size;
size = ROUNDUP(strlen(host) + 1);
vdp->vmt_size = size;
strcpy(vmt2dataptr(vmtp, VMT_HOST), host);
vdprev = vdp;
vdp++;
vdp->vmt_off = vdprev->vmt_off + size;
size = ROUNDUP(strlen(name) + 1);
vdp->vmt_size = size;
strcpy(vmt2dataptr(vmtp, VMT_HOSTNAME), name);
vdprev = vdp;
vdp++;
vdp->vmt_off = vdprev->vmt_off + size;
size = ROUNDUP(strlen(info) + 1);
vdp->vmt_size = size;
strcpy(vmt2dataptr(vmtp, VMT_INFO), info);
vdprev = vdp;
vdp++;
vdp->vmt_off = vdprev->vmt_off + size;
size = ROUNDUP(strlen(args) + 1);
vdp->vmt_size = size;
strcpy(vmt2dataptr(vmtp, VMT_ARGS), args);
BUGLPR(mdebug, BUGACT, ("Exit from vmountdata\n"));
}