-/* Copyright 1998 Transarc Corporation - All Rights Reserved.
- *
- * osi_misc.c
- *
+/*
+ * Copyright 2000, International Business Machines Corporation and others.
+ * All Rights Reserved.
+ *
+ * This software has been released under the terms of the IBM Public
+ * License. For details, see the LICENSE file in the top-level source
+ * directory or online at http://www.openafs.org/dl/license10.html
+ */
+
+/*
* Linux support routines.
*
*/
-#include "../afs/param.h"
-#include "../afs/sysincludes.h"
-#include "../afs/afsincludes.h"
-#include "../afs/afs_stats.h"
+#include <afsconfig.h>
+#include "afs/param.h"
-char *crash_addr = 0; /* Induce an oops by writing here. */
-/* Lookup name and return vnode for same. */
-int osi_lookupname(char *aname, uio_seg_t seg, int followlink,
- vnode_t **dirvpp, struct dentry **dpp)
-{
- struct dentry *dp = NULL;
- int code;
+#include <linux/module.h> /* early to avoid printf->printk mapping */
+#include "h/dcache.h"
+#include "h/namei.h"
+#include "h/kthread.h"
+#include "afs/sysincludes.h"
+#include "afsincludes.h"
+#include "afs/afs_stats.h"
+#include "h/smp_lock.h"
- code = ENOENT;
- if (seg == AFS_UIOUSER) {
- dp = followlink ? namei(aname) : lnamei(aname);
- }
- else {
- dp = lookup_dentry(aname, NULL, followlink ? 1 : 0);
- }
-
- if (dp && !IS_ERR(dp)) {
- if (dp->d_inode) {
- *dpp = dp;
- code = 0;
- }
- else
- dput(dp);
- }
-
- return code;
-}
+int afs_osicred_initialized = 0;
+AFS_UCRED afs_osi_cred;
-/* Intialize cache device info and fragment size for disk cache partition. */
-int osi_InitCacheInfo(char *aname)
+void
+afs_osi_SetTime(osi_timeval_t * tvp)
{
- int code;
- struct dentry *dp;
- extern ino_t cacheInode;
- extern struct osi_dev cacheDev;
- extern afs_int32 afs_fsfragsize;
- extern struct super_block *afs_cacheSBp;
-
- code = osi_lookupname(aname, AFS_UIOSYS, 1, NULL, &dp);
- if (code) return ENOENT;
+ struct timespec tv;
+ tv.tv_sec = tvp->tv_sec;
+ tv.tv_nsec = tvp->tv_usec * NSEC_PER_USEC;
- cacheInode = dp->d_inode->i_ino;
- cacheDev.dev = dp->d_inode->i_dev;
- afs_fsfragsize = dp->d_inode->i_sb->s_blocksize;
- afs_cacheSBp = dp->d_inode->i_sb;
-
- dput(dp);
+ AFS_STATCNT(osi_SetTime);
- return 0;
+ do_settimeofday(&tv);
}
-
-#define FOP_READ(F, B, C) (F)->f_op->read(F, B, (size_t)(C), &(F)->f_pos)
-#define FOP_WRITE(F, B, C) (F)->f_op->write(F, B, (size_t)(C), &(F)->f_pos)
-
-/* osi_rdwr
- * Seek, then read or write to an open inode. addrp points to data in
- * kernel space.
- */
-int osi_rdwr(int rw, struct osi_file *file, caddr_t addrp, size_t asize,
- size_t *resid)
+void
+osi_linux_mask(void)
{
- int code = 0;
- KERNEL_SPACE_DECL;
- struct file *filp = &file->file;
- off_t offset = file->offset;
-
- /* Seek to the desired position. Return -1 on error. */
- if (filp->f_op->llseek) {
- if (filp->f_op->llseek(filp, (loff_t)offset, 0) != offset)
- return -1;
- }
- else
- filp->f_pos = offset;
-
- /* Read/Write the data. */
- TO_USER_SPACE();
- if (rw == UIO_READ)
- code = FOP_READ(filp, addrp, asize);
- else if (rw == UIO_WRITE)
- code = FOP_WRITE(filp, addrp, asize);
- else /* all is well? */
- code = asize;
- TO_KERNEL_SPACE();
-
- if (code >=0) {
- *resid = asize - code;
- return 0;
- }
- else
- return -1;
+ SIG_LOCK(current);
+ sigfillset(¤t->blocked);
+ RECALC_SIGPENDING(current);
+ SIG_UNLOCK(current);
}
-/* This variant is called from AFS read/write routines and takes a uio
- * struct and, if successful, returns 0.
- */
-int osi_file_uio_rdwr(struct osi_file *osifile, uio_t *uiop, int rw)
+/* LOOKUP_POSITIVE is becoming the default */
+#ifndef LOOKUP_POSITIVE
+#define LOOKUP_POSITIVE 0
+#endif
+/* Lookup name and return vnode for same. */
+int
+osi_lookupname_internal(char *aname, int followlink, struct vfsmount **mnt,
+ struct dentry **dpp)
{
- struct file *filp = &osifile->file;
- struct inode *ip = FILE_INODE(&osifile->file);
- KERNEL_SPACE_DECL;
- int code = 0;
- struct iovec *iov;
- int count;
-
- if (uiop->uio_seg == AFS_UIOSYS)
- TO_USER_SPACE();
-
- filp->f_pos = uiop->uio_offset;
- while (code == 0 && uiop->uio_resid > 0 && uiop->uio_iovcnt > 0) {
- iov = uiop->uio_iov;
- count = iov->iov_len;
- if (count == 0) {
- uiop->uio_iov++;
- uiop->uio_iovcnt--;
- continue;
- }
-
- if (rw == UIO_READ)
- code = FOP_READ(filp, iov->iov_base, count);
- else
- code = FOP_WRITE(filp, iov->iov_base, count);
+ int code;
+ struct nameidata nd;
+ int flags = LOOKUP_POSITIVE;
+ code = ENOENT;
- if (code < 0) {
- code = -code;
- break;
- }
-
- iov->iov_base += code;
- iov->iov_len -= code;
- uiop->uio_resid -= code;
- uiop->uio_offset += code;
- code = 0;
+ if (followlink)
+ flags |= LOOKUP_FOLLOW;
+ code = path_lookup(aname, flags, &nd);
+
+ if (!code) {
+#if defined(STRUCT_NAMEIDATA_HAS_PATH)
+ *dpp = dget(nd.path.dentry);
+ if (mnt)
+ *mnt = mntget(nd.path.mnt);
+ path_put(&nd.path);
+#else
+ *dpp = dget(nd.dentry);
+ if (mnt)
+ *mnt = mntget(nd.mnt);
+ path_release(&nd);
+#endif
}
-
- if (uiop->uio_seg == AFS_UIOSYS)
- TO_KERNEL_SPACE();
-
return code;
}
-/* setup_uio
- * Setup a uio struct.
- */
-void setup_uio(uio_t *uiop, struct iovec *iovecp, char *buf,
- int pos, int count, uio_flag_t flag,
- uio_seg_t seg)
+int
+osi_lookupname(char *aname, uio_seg_t seg, int followlink,
+ struct dentry **dpp)
{
- iovecp->iov_base = buf;
- iovecp->iov_len = count;
- uiop->uio_iov = iovecp;
- uiop->uio_iovcnt = 1;
- uiop->uio_offset = pos;
- uiop->uio_seg = seg;
- uiop->uio_resid = count;
- uiop->uio_flag = flag;
+ int code;
+ char *tname;
+ code = ENOENT;
+ if (seg == AFS_UIOUSER) {
+ tname = getname(aname);
+ if (IS_ERR(tname))
+ return PTR_ERR(tname);
+ } else {
+ tname = aname;
+ }
+ code = osi_lookupname_internal(tname, followlink, NULL, dpp);
+ if (seg == AFS_UIOUSER) {
+ putname(tname);
+ }
+ return code;
}
-
-/* uiomove
- * UIO_READ : dp -> uio
- * UIO_WRITE : uio -> dp
- */
-int uiomove(char *dp, int length, uio_flag_t rw, uio_t *uiop)
+int osi_abspath(char *aname, char *buf, int buflen,
+ int followlink, char **pathp)
{
- int count, n;
- struct iovec *iov;
+ struct dentry *dp = NULL;
+ struct vfsmount *mnt = NULL;
+ char *tname, *path;
int code;
- while (length > 0 && uiop->uio_resid > 0 && uiop->uio_iovcnt > 0) {
- iov = uiop->uio_iov;
- count = iov->iov_len;
-
- if (!count) {
- uiop->uio_iov++;
- uiop->uio_iovcnt--;
- continue;
- }
-
- if (count > length)
- count = length;
-
- switch(uiop->uio_seg) {
- case AFS_UIOSYS:
- switch(rw) {
- case UIO_READ:
- memcpy(iov->iov_base, dp, count); break;
- case UIO_WRITE:
- memcpy(dp, iov->iov_base, count); break;
- default:
- printf("uiomove: Bad rw = %d\n", rw);
- return -EINVAL;
- }
- break;
- case AFS_UIOUSER:
- switch(rw) {
- case UIO_READ:
- AFS_COPYOUT(dp, iov->iov_base, count, code); break;
- case UIO_WRITE:
- AFS_COPYIN(iov->iov_base, dp, count, code); break;
- default:
- printf("uiomove: Bad rw = %d\n", rw);
- return -EINVAL;
- }
- break;
- default:
- printf("uiomove: Bad seg = %d\n", uiop->uio_seg);
- return -EINVAL;
+ code = ENOENT;
+ tname = getname(aname);
+ if (IS_ERR(tname))
+ return -PTR_ERR(tname);
+ code = osi_lookupname_internal(tname, followlink, &mnt, &dp);
+ if (!code) {
+#if defined(D_PATH_TAKES_STRUCT_PATH)
+ struct path p = { mnt, dp };
+ path = d_path(&p, buf, buflen);
+#else
+ path = d_path(dp, mnt, buf, buflen);
+#endif
+
+ if (IS_ERR(path)) {
+ code = -PTR_ERR(path);
+ } else {
+ *pathp = path;
}
- dp += count;
- length -= count;
- iov->iov_base += count;
- iov->iov_len -= count;
- uiop->uio_offset += count;
- uiop->uio_resid -= count;
+ dput(dp);
+ mntput(mnt);
}
- return 0;
-}
-
-void afs_osi_SetTime(osi_timeval_t *tvp)
-{
- extern int (*sys_settimeofdayp)(struct timeval *tv, struct timezone *tz);
- KERNEL_SPACE_DECL;
-
- AFS_STATCNT(osi_SetTime);
- TO_USER_SPACE();
- (void) (*sys_settimeofdayp)(tvp, NULL);
- TO_KERNEL_SPACE();
+ putname(tname);
+ return code;
}
-/* Free all the pages on any of the vnodes in the vlru. Must be done before
- * freeing all memory.
- */
-void osi_linux_free_inode_pages(void)
-{
- int i;
- struct vcache *tvc;
- struct inode *ip;
- extern struct vcache *afs_vhashT[VCSIZE];
-
- for (i=0; i<VCSIZE; i++) {
- for(tvc = afs_vhashT[i]; tvc; tvc=tvc->hnext) {
- ip = (struct inode*)tvc;
- if (ip->i_nrpages) {
- invalidate_inode_pages(ip);
- if (ip->i_nrpages) {
- printf("Failed to invalidate all pages on inode 0x%x\n",
- ip);
- }
- }
- }
- }
-}
-/* iput an inode. Since we still have a separate inode pool, we don't want
- * to call iput on AFS inodes, since they would then end up on Linux's
- * inode_unsed list.
- */
-void osi_iput(struct inode *ip)
+/* This could use some work, and support on more platforms. */
+int afs_thread_wrapper(void *rock)
{
- extern void afs_delete_inode(struct inode *ip);
- extern struct vfs *afs_globalVFS;
-
-
- if (ip->i_count == 0 || ip->i_count & 0xffff0000) {
- osi_Panic("IPUT Bad refCount %d on inode 0x%x\n",
- ip->i_count, ip);
- }
- if (afs_globalVFS && afs_globalVFS == ip->i_sb ) {
- ip->i_count --;
- if (!ip->i_count)
- afs_delete_inode(ip);
- }
- else {
- iput(ip);
- }
+ void (*proc)(void) = rock;
+ __module_get(THIS_MODULE);
+ AFS_GLOCK();
+ (*proc)();
+ AFS_GUNLOCK();
+ module_put(THIS_MODULE);
+ return 0;
}
-/* check_bad_parent() : Checks if this dentry's vcache is a root vcache
- * that has its mvid (parent dir's fid) pointer set to the wrong directory
- * due to being mounted in multiple points at once. If so, check_bad_parent()
- * calls afs_lookup() to correct the vcache's mvid, as well as the volume's
- * dotdotfid and mtpoint fid members.
- * Parameters:
- * dp - dentry to be checked.
- * Return Values:
- * None.
- * Sideeffects:
- * This dentry's vcache's mvid will be set to the correct parent directory's
- * fid.
- * This root vnode's volume will have its dotdotfid and mtpoint fids set
- * to the correct parent and mountpoint fids.
- */
-
-void check_bad_parent(struct dentry *dp)
+void afs_start_thread(void (*proc)(void), char *name)
{
- cred_t *credp;
- struct vcache *vcp = (struct vcache*)dp->d_inode, *avc = NULL;
- struct vcache *pvc = (struct vcache *)dp->d_parent->d_inode;
-
- if (vcp->mvid->Fid.Volume != pvc->fid.Fid.Volume) { /* bad parent */
- credp = crref();
-
-
- /* force a lookup, so vcp->mvid is fixed up */
- afs_lookup(pvc, dp->d_name.name, &avc, credp);
- if (!avc || vcp != avc) { /* bad, very bad.. */
- afs_Trace4(afs_iclSetp, CM_TRACE_TMP_1S3L, ICL_TYPE_STRING,
- "afs_linux_revalidate : bad pointer returned from afs_lookup origvc newvc dentry",
- ICL_TYPE_POINTER, vcp,
- ICL_TYPE_POINTER, avc,
- ICL_TYPE_POINTER, dp);
- }
-
- } /* if bad parent */
-
- return;
+ kthread_run(afs_thread_wrapper, proc, "%s", name);
}