/* * 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 */ /* * SOLARIS inode operations * * Implements: * */ #include #include "afs/param.h" #include "afs/sysincludes.h" /* Standard vendor system headers */ #include "afsincludes.h" /* Afs-based standard headers */ #include "afs/osi_inode.h" #include "afs/afs_stats.h" /* statistics stuff */ extern int (*ufs_iallocp) (), (*ufs_iupdatp) (), (*ufs_igetp) (), (*ufs_itimes_nolockp) (); #define AFS_ITIMES(ip) { \ mutex_enter(&(ip)->i_tlock); \ (*ufs_itimes_nolockp)(ip); \ mutex_exit(&(ip)->i_tlock); \ } #define AFS_ITIMES_NOLOCK(ip) \ (*ufs_itimes_nolockp)(ip); getinode(vfsp, dev, inode, ipp, credp, perror) struct vfs *vfsp; afs_ucred_t *credp; struct inode **ipp; dev_t dev; ino_t inode; int *perror; { struct inode *ip; afs_int32 code; struct vnode *vp; struct fs *fs; struct inode *pip; struct ufsvfs *ufsvfsp; AFS_STATCNT(getinode); *perror = 0; if (!vfsp && !(vfsp = vfs_dev2vfsp(dev))) { return (ENODEV); } ufsvfsp = (struct ufsvfs *)vfsp->vfs_data; #ifdef HAVE_VFS_DQRWLOCK rw_enter(&ufsvfsp->vfs_dqrwlock, RW_READER); #endif code = (*ufs_igetp) (vfsp, inode, &ip, credp); #ifdef HAVE_VFS_DQRWLOCK rw_exit(&ufsvfsp->vfs_dqrwlock); #endif if (code) { *perror = BAD_IGET; return code; } *ipp = ip; return code; } /* get an existing inode. Common code for iopen, iread/write, iinc/dec. */ igetinode(vfsp, dev, inode, ipp, credp, perror) afs_ucred_t *credp; struct inode **ipp; struct vfs *vfsp; dev_t dev; ino_t inode; int *perror; { struct inode *pip, *ip; extern struct osi_dev cacheDev; int code = 0; *perror = 0; AFS_STATCNT(igetinode); code = getinode(vfsp, dev, inode, &ip, credp, perror); if (code) return code; rw_enter(&ip->i_contents, RW_READER); if (ip->i_mode == 0) { /* Not an allocated inode */ rw_exit(&ip->i_contents); VN_RELE(ITOV(ip)); return (ENOENT); } if (ip->i_nlink == 0 || (ip->i_mode & IFMT) != IFREG) { AFS_ITIMES(ip); rw_exit(&ip->i_contents); VN_RELE(ITOV(ip)); return (ENOENT); } /* On VFS40 systems, iput does major synchronous write action, but only * when the reference count on the vnode goes to 0. Normally, Sun users * don't notice this because the DNLC keep references for them, but we * notice 'cause we don't. So, we make a fake dnlc entry which gets * cleaned up by iget when it needs the space. */ if (dev != cacheDev.dev) { /* * Don't call dnlc for the cm inodes since it's a big performance * penalty there! */ #ifdef AFS_SUN510_ENV dnlc_enter(ITOV(ip), "a", ITOV(ip)); #else dnlc_enter(ITOV(ip), "a", ITOV(ip), (afs_ucred_t *)0); #endif } *ipp = ip; rw_exit(&ip->i_contents); return (code); } int CrSync = 1; afs_syscall_icreate(dev, near_inode, param1, param2, param3, param4, rvp, credp) rval_t *rvp; afs_ucred_t *credp; long near_inode, param1, param2, param3, param4; dev_t dev; { int dummy, err = 0; struct inode *ip, *newip; int code; dev_t newdev; struct ufsvfs *ufsvfsp; AFS_STATCNT(afs_syscall_icreate); if (!afs_osi_suser(credp)) return (EPERM); /** Code to convert a 32 bit dev_t into a 64 bit dev_t * This conversion is needed only for the 64 bit OS. */ #ifdef AFS_SUN5_64BIT_ENV newdev = expldev((dev32_t) dev); #else newdev = dev; #endif code = getinode(0, (dev_t) newdev, 2, &ip, credp, &dummy); if (code) { return (code); } ufsvfsp = ip->i_ufsvfs; rw_enter(&ip->i_rwlock, RW_WRITER); #ifdef HAVE_VFS_DQRWLOCK rw_enter(&ufsvfsp->vfs_dqrwlock, RW_READER); #endif rw_enter(&ip->i_contents, RW_WRITER); code = (*ufs_iallocp) (ip, near_inode, 0, &newip, credp); AFS_ITIMES_NOLOCK(ip); rw_exit(&ip->i_contents); #ifdef HAVE_VFS_DQRWLOCK rw_exit(&ufsvfsp->vfs_dqrwlock); #endif rw_exit(&ip->i_rwlock); VN_RELE(ITOV(ip)); if (code) { return (code); } rw_enter(&newip->i_contents, RW_WRITER); newip->i_flag |= IACC | IUPD | ICHG; newip->i_vicemagic = VICEMAGIC; newip->i_nlink = 1; newip->i_mode = IFREG; #ifdef AFS_SUN510_ENV newip->i_vnode->v_type = VREG; #else newip->i_vnode.v_type = VREG; #endif newip->i_vicep1 = param1; if (param2 == 0x1fffffff /*INODESPECIAL*/) { newip->i_vicep2 = ((0x1fffffff << 3) + (param4 & 0x3)); newip->i_vicep3 = param3; } else { newip->i_vicep2 = (((param2 >> 16) & 0x1f) << 27) + (((param4 >> 16) & 0x1f) << 22) + (param3 & 0x3fffff); newip->i_vicep3 = ((param4 << 16) + (param2 & 0xffff)); } #ifdef AFS_SUN5_64BIT_ENV rvp->r_vals = newip->i_number; #else rvp->r_val1 = newip->i_number; #endif /* * We're being conservative and sync to the disk */ if (CrSync) (*ufs_iupdatp) (newip, 1); AFS_ITIMES_NOLOCK(newip); rw_exit(&newip->i_contents); VN_RELE(ITOV(newip)); return (code); } afs_syscall_iopen(dev, inode, usrmod, rvp, credp) rval_t *rvp; afs_ucred_t *credp; int inode, usrmod; dev_t dev; { struct file *fp; struct inode *ip; struct vnode *vp = NULL; int dummy; int fd; int code; dev_t newdev; AFS_STATCNT(afs_syscall_iopen); if (!afs_osi_suser(credp)) return (EPERM); /** Code to convert a 32 bit dev_t into a 64 bit dev_t * This conversion is needed only for the 64 bit OS. */ #ifdef AFS_SUN5_64BIT_ENV newdev = expldev((dev32_t) dev); #else newdev = dev; #endif code = igetinode(0, (dev_t) newdev, (ino_t) inode, &ip, credp, &dummy); if (code) { return (code); } code = falloc((struct vnode *)NULL, FWRITE | FREAD, &fp, &fd); if (code) { rw_enter(&ip->i_contents, RW_READER); AFS_ITIMES(ip); rw_exit(&ip->i_contents); VN_RELE(ITOV(ip)); return (code); } /* fp->f_count, f_audit_data are set by falloc */ fp->f_vnode = ITOV(ip); fp->f_flag = (usrmod + 1) & (FMASK); /* fp->f_count, f_msgcount are set by falloc */ /* fp->f_offset zeroed by falloc */ /* f_cred set by falloc */ /* * falloc returns the fp write locked */ mutex_exit(&fp->f_tlock); /* * XXX We should set the fp to null since we don't need it in the icalls */ setf(fd, fp); /* rvp->r_val{1,2} are really members into a union and are re-extracted * later by solaris. If we're not 64-bit, they appear to just be the same * thing, but on 64-bit they point to two different 32-bit locations that * make up one 64-bit int; so on 64-bit big-endian we need to set the * second one. */ #if defined(AFS_SUN5_64BIT_ENV) && !defined(AFSLITTLE_ENDIAN) rvp->r_val2 = fd; #else rvp->r_val1 = fd; #endif return code; } int IncSync = 1; afs_syscall_iincdec(dev, inode, inode_p1, amount, rvp, credp) rval_t *rvp; afs_ucred_t *credp; int inode, inode_p1, amount; dev_t dev; { int dummy; struct inode *ip; afs_int32 code; dev_t newdev; if (!afs_osi_suser(credp)) return (EPERM); /** Code to convert a 32 bit dev_t into a 64 bit dev_t * This conversion is needed only for the 64 bit OS. */ #ifdef AFS_SUN5_64BIT_ENV newdev = expldev((dev32_t) dev); #else newdev = dev; #endif code = igetinode(0, (dev_t) newdev, (ino_t) inode, &ip, credp, &dummy); if (code) { return (code); } if (!IS_VICEMAGIC(ip)) { code = EPERM; rw_enter(&ip->i_contents, RW_READER); AFS_ITIMES(ip); rw_exit(&ip->i_contents); VN_RELE(ITOV(ip)); } else { rw_enter(&ip->i_contents, RW_WRITER); ip->i_nlink += amount; if (ip->i_nlink == 0) { /* remove the "a" name added by igetinode so that the space is reclaimed. */ dnlc_remove(ITOV(ip), "a"); CLEAR_VICEMAGIC(ip); } ip->i_flag |= ICHG; /* We may want to force the inode to the disk in case of crashes, other references, etc. */ if (IncSync) (*ufs_iupdatp) (ip, 1); AFS_ITIMES_NOLOCK(ip); rw_exit(&ip->i_contents); VN_RELE(ITOV(ip)); } return (code); }