fix-linux22-20050310
[openafs.git] / src / afs / LINUX / osi_misc.c
index 7c928bc..440351c 100644 (file)
@@ -23,54 +23,66 @@ RCSID
 #if defined(AFS_LINUX24_ENV)
 #include "h/smp_lock.h"
 #endif
-
-char *crash_addr = 0;          /* Induce an oops by writing here. */
+#if defined(AFS_LINUX26_ENV)
+#include "h/namei.h"
+#endif
 
 #if defined(AFS_LINUX24_ENV)
+/* 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, uio_seg_t seg, int followlink,
-                       vnode_t ** dirvpp, struct dentry **dpp,
-                       struct nameidata *nd)
+osi_lookupname_internal(char *aname, int followlink, struct vfsmount **mnt,
+                       struct dentry **dpp)
 {
     int code;
+    struct nameidata nd;
+    int flags = LOOKUP_POSITIVE;
+    code = ENOENT;
+
+    if (followlink)
+       flags |= LOOKUP_FOLLOW;
+#if defined(AFS_LINUX26_ENV)
+    code = path_lookup(aname, flags, &nd);
+#else
+    if (path_init(aname, flags, &nd))
+        code = path_walk(aname, &nd);
+#endif
 
+    if (!code) {
+       *dpp = dget(nd.dentry);
+        if (mnt)
+           *mnt = mntget(nd.mnt);
+       path_release(&nd);
+    }
+    return code;
+}
+int
+osi_lookupname(char *aname, uio_seg_t seg, int followlink, 
+                       struct dentry **dpp)
+{
+    int code;
+    char *tname;
     code = ENOENT;
     if (seg == AFS_UIOUSER) {
-       code =
-           followlink ? user_path_walk(aname,
-                                       nd) : user_path_walk_link(aname, nd);
+        tname = getname(aname);
+        if (IS_ERR(tname)) 
+            return PTR_ERR(tname);
     } else {
-       if (path_init(aname, followlink ? LOOKUP_FOLLOW : 0, nd))
-           code = path_walk(aname, nd);
+        tname = aname;
     }
-
-    if (!code) {
-       if (nd->dentry->d_inode) {
-           *dpp = dget(nd->dentry);
-           code = 0;
-       } else {
-           code = ENOENT;
-           path_release(nd);
-       }
+    code = osi_lookupname_internal(tname, followlink, NULL, dpp);   
+    if (seg == AFS_UIOUSER) {
+        putname(tname);
     }
     return code;
 }
-#endif
-
+#else
 int
-osi_lookupname(char *aname, uio_seg_t seg, int followlink, vnode_t ** dirvpp,
-              struct dentry **dpp)
+osi_lookupname(char *aname, uio_seg_t seg, int followlink, struct dentry **dpp)
 {
-#if defined(AFS_LINUX24_ENV)
-    struct nameidata nd;
-    int code = osi_lookupname_internal(aname, seg, followlink, dirvpp, dpp,
-                                      &nd);
-    if (!code)
-       path_release(&nd);
-
-    return (code);
-#else
     struct dentry *dp = NULL;
     int code;
 
@@ -90,29 +102,26 @@ osi_lookupname(char *aname, uio_seg_t seg, int followlink, vnode_t ** dirvpp,
     }
 
     return code;
-#endif
 }
+#endif
 
 /* Intialize cache device info and fragment size for disk cache partition. */
 int
 osi_InitCacheInfo(char *aname)
 {
     int code;
-    struct dentry *dp;
+    struct dentry *dp,*dpp;
     extern ino_t cacheInode;
     extern struct osi_dev cacheDev;
     extern afs_int32 afs_fsfragsize;
     extern struct super_block *afs_cacheSBp;
-    extern struct nameidata afs_cacheNd;
-
-    code =
-       osi_lookupname_internal(aname, AFS_UIOSYS, 1, NULL, &dp,
-                               &afs_cacheNd);
+    extern struct vfsmnt *afs_cacheMnt;
+    code = osi_lookupname_internal(aname, 1, &afs_cacheMnt, &dp);
     if (code)
        return ENOENT;
 
     cacheInode = dp->d_inode->i_ino;
-    cacheDev.dev = dp->d_inode->i_dev;
+    cacheDev.dev = dp->d_inode->i_sb->s_dev;
     afs_fsfragsize = dp->d_inode->i_sb->s_blocksize - 1;
     afs_cacheSBp = dp->d_inode->i_sb;
 
@@ -146,8 +155,8 @@ osi_rdwr(int rw, struct osi_file *file, caddr_t addrp, size_t asize,
     } else
        filp->f_pos = offset;
 
-    savelim = current->rlim[RLIMIT_FSIZE].rlim_cur;
-    current->rlim[RLIMIT_FSIZE].rlim_cur = RLIM_INFINITY;
+    savelim = current->TASK_STRUCT_RLIM[RLIMIT_FSIZE].rlim_cur;
+    current->TASK_STRUCT_RLIM[RLIMIT_FSIZE].rlim_cur = RLIM_INFINITY;
 
     /* Read/Write the data. */
     TO_USER_SPACE();
@@ -159,7 +168,7 @@ osi_rdwr(int rw, struct osi_file *file, caddr_t addrp, size_t asize,
        code = asize;
     TO_KERNEL_SPACE();
 
-    current->rlim[RLIMIT_FSIZE].rlim_cur = savelim;
+    current->TASK_STRUCT_RLIM[RLIMIT_FSIZE].rlim_cur = savelim;
 
     if (code >= 0) {
        *resid = asize - code;
@@ -175,15 +184,14 @@ int
 osi_file_uio_rdwr(struct osi_file *osifile, uio_t * uiop, int rw)
 {
     struct file *filp = &osifile->file;
-    struct inode *ip = FILE_INODE(&osifile->file);
     KERNEL_SPACE_DECL;
     int code = 0;
     struct iovec *iov;
     int count;
     unsigned long savelim;
 
-    savelim = current->rlim[RLIMIT_FSIZE].rlim_cur;
-    current->rlim[RLIMIT_FSIZE].rlim_cur = RLIM_INFINITY;
+    savelim = current->TASK_STRUCT_RLIM[RLIMIT_FSIZE].rlim_cur;
+    current->TASK_STRUCT_RLIM[RLIMIT_FSIZE].rlim_cur = RLIM_INFINITY;
 
     if (uiop->uio_seg == AFS_UIOSYS)
        TO_USER_SPACE();
@@ -206,6 +214,14 @@ osi_file_uio_rdwr(struct osi_file *osifile, uio_t * uiop, int rw)
        if (code < 0) {
            code = -code;
            break;
+       } else if (code == 0) {
+           /*
+            * This is bad -- we can't read any more data from the
+            * file, but we have no good way of signaling a partial
+            * read either.
+            */
+           code = EIO;
+           break;
        }
 
        iov->iov_base += code;
@@ -218,7 +234,7 @@ osi_file_uio_rdwr(struct osi_file *osifile, uio_t * uiop, int rw)
     if (uiop->uio_seg == AFS_UIOSYS)
        TO_KERNEL_SPACE();
 
-    current->rlim[RLIMIT_FSIZE].rlim_cur = savelim;
+    current->TASK_STRUCT_RLIM[RLIMIT_FSIZE].rlim_cur = savelim;
 
     return code;
 }
@@ -227,10 +243,10 @@ osi_file_uio_rdwr(struct osi_file *osifile, uio_t * uiop, int rw)
  * Setup a uio struct.
  */
 void
-setup_uio(uio_t * uiop, struct iovec *iovecp, char *buf, afs_offs_t pos,
+setup_uio(uio_t * uiop, struct iovec *iovecp, const char *buf, afs_offs_t pos,
          int count, uio_flag_t flag, uio_seg_t seg)
 {
-    iovecp->iov_base = buf;
+    iovecp->iov_base = (char *)buf;
     iovecp->iov_len = count;
     uiop->uio_iov = iovecp;
     uiop->uio_iovcnt = 1;
@@ -248,7 +264,7 @@ setup_uio(uio_t * uiop, struct iovec *iovecp, char *buf, afs_offs_t pos,
 int
 uiomove(char *dp, int length, uio_flag_t rw, uio_t * uiop)
 {
-    int count, n;
+    int count;
     struct iovec *iov;
     int code;
 
@@ -310,21 +326,32 @@ uiomove(char *dp, int length, uio_flag_t rw, uio_t * uiop)
 void
 afs_osi_SetTime(osi_timeval_t * tvp)
 {
-    extern int (*sys_settimeofdayp) (struct timeval * tv,
-                                    struct timezone * tz);
-#ifdef AFS_LINUX_64BIT_KERNEL
+#if defined(AFS_LINUX24_ENV)
+
+#if defined(AFS_LINUX26_ENV)
+    struct timespec tv;
+    tv.tv_sec = tvp->tv_sec;
+    tv.tv_nsec = tvp->tv_usec * NSEC_PER_USEC;
+#else
     struct timeval tv;
-    AFS_STATCNT(osi_SetTime);
     tv.tv_sec = tvp->tv_sec;
     tv.tv_usec = tvp->tv_usec;
-    (void)(*sys_settimeofdayp) (&tv, NULL);
+#endif
+
+    AFS_STATCNT(osi_SetTime);
+
+    do_settimeofday(&tv);
 #else
+    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);
+    if (sys_settimeofdayp)
+       (void)(*sys_settimeofdayp) (tvp, NULL);
     TO_KERNEL_SPACE();
 #endif
 }
@@ -360,8 +387,8 @@ osi_linux_free_inode_pages(void)
 #else
                if (ip->i_nrpages) {
 #endif
-                   printf("Failed to invalidate all pages on inode 0x%x\n",
-                          ip);
+                   printf("Failed to invalidate all pages on inode 0x%lx\n",
+                          (unsigned long)ip);
                }
            }
        }
@@ -376,24 +403,26 @@ osi_clear_inode(struct inode *ip)
 
 #if defined(AFS_LINUX24_ENV)
     if (atomic_read(&ip->i_count) > 1)
+       printf("afs_put_inode: ino %ld (0x%lx) has count %ld\n",
+              (long)ip->i_ino, (unsigned long)ip,
+              (long)atomic_read(&ip->i_count));
 #else
     if (ip->i_count > 1)
+       printf("afs_put_inode: ino %ld (0x%lx) has count %ld\n",
+              (long)ip->i_ino, (unsigned long)ip, (long)ip->i_count);
 #endif
-       printf("afs_put_inode: ino %d (0x%x) has count %d\n", ip->i_ino, ip,
-              ip->i_count);
 
     afs_InactiveVCache(vcp, credp);
     ObtainWriteLock(&vcp->lock, 504);
-#if defined(AFS_LINUX24_ENV)
-    atomic_set(&ip->i_count, 0);
-#else
-    ip->i_count = 0;
-#endif
     ip->i_nlink = 0;           /* iput checks this after calling this routine. */
+#ifdef I_CLEAR
+    ip->i_state = I_CLEAR;
+#endif
     ReleaseWriteLock(&vcp->lock);
     crfree(credp);
 }
 
+#if !defined(AFS_LINUX26_ENV)
 /* 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.
@@ -404,32 +433,35 @@ osi_iput(struct inode *ip)
     extern struct vfs *afs_globalVFS;
 
     AFS_GLOCK();
+
+    if (afs_globalVFS && ip->i_sb != afs_globalVFS)
+       osi_Panic("IPUT Not an afs inode\n");
+
 #if defined(AFS_LINUX24_ENV)
-    if (atomic_read(&ip->i_count) == 0
-       || atomic_read(&ip->i_count) & 0xffff0000) {
+    if (atomic_read(&ip->i_count) == 0)
 #else
-    if (ip->i_count == 0 || ip->i_count & 0xffff0000) {
+    if (ip->i_count == 0)
 #endif
        osi_Panic("IPUT Bad refCount %d on inode 0x%x\n",
 #if defined(AFS_LINUX24_ENV)
-                 atomic_read(&ip->i_count), ip);
+                 atomic_read(&ip->i_count),
 #else
-                 ip->i_count, ip);
+                 ip->i_count,
 #endif
-    }
-    if (afs_globalVFS && afs_globalVFS == ip->i_sb) {
+                               ip);
+
 #if defined(AFS_LINUX24_ENV)
-       atomic_dec(&ip->i_count);
-       if (!atomic_read(&ip->i_count))
+    if (atomic_dec_and_test(&ip->i_count))
 #else
-       ip->i_count--;
-       if (!ip->i_count)
+    if (!--ip->i_count)
 #endif
-           osi_clear_inode(ip);
-    } else
-       iput(ip);
+                                          {
+       osi_clear_inode(ip);
+       ip->i_state = 0;
+    }
     AFS_GUNLOCK();
 }
+#endif
 
 /* 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
@@ -462,7 +494,7 @@ check_bad_parent(struct dentry *dp)
        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",
+                      "check_bad_parent: bad pointer returned from afs_lookup origvc newvc dentry",
                       ICL_TYPE_POINTER, vcp, ICL_TYPE_POINTER, avc,
                       ICL_TYPE_POINTER, dp);
        }