/*************************************************************************** * * Copyright (C) 2001 International Business Machines * All rights reserved. * * This file is part of the GPFS mmfslinux kernel module. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written * permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * *************************************************************************** */ /* @(#)39 1.56.1.2 src/avs/fs/mmfs/ts/kernext/gpl-linux/kx.c, mmfs, avs_rgpfs24, rgpfs24s007a 10/25/06 17:52:27 */ #include #ifdef MODULE #include #endif #include #include #include #include #include #include #include #include #include #include #ifndef GPFS_ARCH_X86_64 /* grab stuff for madvise */ #define __KERNEL_SYSCALLS__ #endif #include #include #include #include #include #include #include #include #include #include #include #ifdef API_32BIT /* Equivalent structure for stat64 at 32-bit user level (for API remapping) */ /* gcc doesn't align double words with i386/ia32 like it does for ia64, so * we need to adjust for this. */ /* Ideally we would include a header file with this definition (ia32.h) instead of defining it ourselves, but this typically breaks things (such as with x86_64). */ typedef struct stat64_user32 { UInt64 st_dev; UInt32 __pad1; UInt32 __st_ino; UInt32 st_mode; UInt32 st_nlink; UInt32 st_uid; UInt32 st_gid; UInt64 st_rdev; UInt32 __pad2; UInt32 st_size_lower; /* break up st_size to avoid extra padding */ UInt32 st_size_upper; /* w/ little Endian ordering */ UInt32 st_blksize; UInt64 st_blocks; UInt32 st_atime; UInt32 __unused1; UInt32 st_mtime; UInt32 __unused2; UInt32 st_ctime; UInt32 __unused3; UInt64 st_ino; } stat64_user32; #endif /* API_32BIT */ /* check if inode belongs to GPFS */ #define GPFS_TYPE(IP) (!(iP) ? false : \ (!(iP->i_sb) ? false : \ (!(iP->i_sb->s_type) ? false : \ !strcmp(iP->i_sb->s_type->name, "gpfs")))) int kxPoll(void* fdListP, int nFDs, int timeoutMS) { return -ENOSYS; } int cleanupFD = 0; extern struct super_block *shutdownSuperP; #ifdef API_32BIT static void vstat32(cxiVattr_t *vattrp, struct stat64_user32 *statbuf) { ENTER(0); memset(statbuf, 0, sizeof(struct stat64_user32)); statbuf->st_dev = vattrp->va_dev; statbuf->st_ino = vattrp->va_serialno; statbuf->st_mode = vattrp->va_mode; statbuf->st_nlink = vattrp->va_nlink; statbuf->st_uid = vattrp->va_uid; statbuf->st_gid = vattrp->va_gid; statbuf->st_rdev = vattrp->va_rdev; statbuf->st_size_upper = High32(vattrp->va_size); statbuf->st_size_lower = Low32(vattrp->va_size); statbuf->st_atime = vattrp->va_atime.tv_sec; statbuf->st_mtime = vattrp->va_mtime.tv_sec; statbuf->st_ctime = vattrp->va_ctime.tv_sec; statbuf->st_blksize = vattrp->va_blocksize; statbuf->st_blocks = vattrp->va_blocks; /* STAT64_HAS_BROKEN_ST_INO is set on i386 ... */ statbuf->__st_ino = vattrp->va_serialno; EXIT(0); } #endif /* API_32BIT */ void static vstat(cxiVattr_t *vattrp, struct stat64 *statbuf) { ENTER(0); memset(statbuf, 0, sizeof(struct stat64)); statbuf->st_dev = vattrp->va_dev; statbuf->st_ino = vattrp->va_serialno; statbuf->st_mode = vattrp->va_mode; statbuf->st_nlink = vattrp->va_nlink; statbuf->st_uid = vattrp->va_uid; statbuf->st_gid = vattrp->va_gid; statbuf->st_rdev = vattrp->va_rdev; statbuf->st_size = vattrp->va_size; statbuf->st_atime = vattrp->va_atime.tv_sec; statbuf->st_mtime = vattrp->va_mtime.tv_sec; statbuf->st_ctime = vattrp->va_ctime.tv_sec; statbuf->st_blksize = vattrp->va_blocksize; statbuf->st_blocks = vattrp->va_blocks; #ifdef STAT64_HAS_BROKEN_ST_INO /* Linux has 2 struct stat64 definitions: 1) /usr/include/asm/stat.h 2) /usr/include/bits/stat.h Of course, they differ 1) st_dev & st_rdev is 2 bytes in (1) and 8 bytes in (2), but the 2 definitions overlap. 2) st_ino is 8 bytes in (1) and 4 bytes in (2) and they are in different places! Fortunately, (1) defines an ifdef telling us to assign st_ino to a second variable which just happens to exactly match the definition in (2). */ statbuf->__st_ino = vattrp->va_serialno; #endif EXIT(0); } #ifdef GPFS_ARCH_PPC64 void static vstat_ppc64(cxiVattr_t *vattrp, struct stat *statbuf) { ENTER(0); memset(statbuf, 0, sizeof(struct stat)); statbuf->st_dev = vattrp->va_dev; statbuf->st_ino = vattrp->va_serialno; statbuf->st_mode = vattrp->va_mode; statbuf->st_nlink = vattrp->va_nlink; statbuf->st_uid = vattrp->va_uid; statbuf->st_gid = vattrp->va_gid; statbuf->st_rdev = vattrp->va_rdev; statbuf->st_size = vattrp->va_size; statbuf->st_atime = vattrp->va_atime.tv_sec; statbuf->st_mtime = vattrp->va_mtime.tv_sec; statbuf->st_ctime = vattrp->va_ctime.tv_sec; statbuf->st_blksize = vattrp->va_blocksize; statbuf->st_blocks = vattrp->va_blocks; EXIT(0); } #endif /* GPFS_ARCH_PPC64 */ /* a call to return exact file status information * using the file's pathname; */ int tsstat(char *pathname, struct stat64 *statP) { struct gpfsVfsData_t *privVfsP; cxiNode_t *cnP; int code = 0; int rc = 0; struct nameidata nd; struct inode *iP; Boolean relePath = false; cxiVattr_t vattr; #ifdef GPFS_ARCH_PPC64 struct stat statbuf; #else struct stat64 statbuf; #endif #ifdef API_32BIT stat64_user32 statbuf32; #endif ENTER(0); if (pathname == NULL || statP == NULL) { code = 1; rc = EINVAL; goto xerror; } rc = user_path_walk(pathname, &nd); if (rc) { rc = -rc; code = 2; goto xerror; } relePath = true; iP = nd.dentry->d_inode; DBGASSERT(iP != NULL); TRACE2(TRACE_VNODE, 1, TRCID_LINUXOPS_TSSTAT_ENTER, "tsstat enter: iP 0x%lX statP 0x%lX\n", iP, statP); if (!GPFS_TYPE(iP)) { code = 3; rc = EINVAL; goto xerror; } privVfsP = VP_TO_PVP(iP); if (privVfsP == NULL) { code = 4; rc = ENOENT; goto xerror; } cnP = VP_TO_CNP(iP); rc = gpfs_ops.gpfsGetattr(privVfsP, cnP, &vattr, true); vattr.va_rdev = cxiDev32ToDev(vattr.va_rdev); if (rc == 0) { #ifdef API_32BIT /* Need to remap? */ if (cxiIS64U((char *)statP)) { vstat(&vattr, &statbuf); rc = cxiCopyOut((char *)&statbuf, (char *)statP, sizeof(struct stat64)); } else { /* Need to remap for 32-bit API call */ vstat32(&vattr, &statbuf32); rc = cxiCopyOut((char *)&statbuf32, (char *)statP, sizeof(struct stat64_user32)); } #else #ifdef GPFS_ARCH_PPC64 /* On ppc64, struct stat64 layout is different for a 64-bit user app and kernel, and we can't use it for copying data out. However, struct stat has the same layout in kernel and 64-bit userspace, and is identical to struct stat64 in 64-bit userspace, so we use it for copyout. */ vstat_ppc64(&vattr, &statbuf); #else vstat(&vattr, &statbuf); #endif rc = cxiCopyOut((char *)&statbuf, (char *)statP, sizeof(statbuf)); #endif /* API_32BIT */ if (rc != 0) { code = 5; goto xerror; } } xerror: if (relePath) path_release(&nd); TRACE2(TRACE_VNODE, 1, TRCID_LINUXOPS_TSSTAT_EXIT, "tsstat exit: code %d rc %d\n", code, rc); EXIT(0); return -rc; } int tsfstat(int fileDesc, struct stat64 *statP) { struct gpfsVfsData_t *privVfsP; cxiNode_t *cnP; struct file *fP; struct inode *iP; int code = 0; int rc; Boolean releFile = false; cxiVattr_t vattr; #ifdef GPFS_ARCH_PPC64 struct stat statbuf; #else struct stat64 statbuf; #endif #ifdef API_32BIT struct stat64_user32 statbuf32; #endif /* API_32BIT */ ENTER(0); if (statP == NULL) { code = 1; rc = EINVAL; goto xerror; } fP = fget(fileDesc); if (!fP) { code = 2; rc = EBADF; goto xerror; } releFile = true; iP = fP->f_dentry->d_inode; DBGASSERT(iP != NULL); TRACE4(TRACE_VNODE, 1, TRCID_LINUXOPS_TSFSTAT_ENTER, "tsfstat enter: fd %d fP 0x%lX iP 0x%lX statP 0x%lX\n", fileDesc, fP, iP, statP); if (!GPFS_TYPE(iP)) { code = 3; rc = EINVAL; goto xerror; } privVfsP = VP_TO_PVP(iP); if (privVfsP == NULL) { code = 4; rc = ENOENT; goto xerror; } cnP = VP_TO_CNP(iP); rc = gpfs_ops.gpfsGetattr(privVfsP, cnP, &vattr, true); vattr.va_rdev = cxiDev32ToDev(vattr.va_rdev); if (rc == 0) { #ifdef API_32BIT /* Need to remap? */ if (cxiIS64U((char *)statP)) { vstat(&vattr, &statbuf); rc = cxiCopyOut((char *)&statbuf, (char *)statP, sizeof(struct stat64)); } else { /* Need to remap for 32-bit API call */ vstat32(&vattr, &statbuf32); rc = cxiCopyOut((char *)&statbuf32, (char *)statP, sizeof(struct stat64_user32)); } #else #ifdef GPFS_ARCH_PPC64 /* On ppc64, struct stat64 layout is different for a 64-bit user app and kernel, and we can't use it for copying data out. However, struct stat has the same layout in kernel and 64-bit userspace, and is identical to struct stat64 in 64-bit userspace, so we use it for copyout. */ vstat_ppc64(&vattr, &statbuf); #else vstat(&vattr, &statbuf); #endif rc = cxiCopyOut((char *)&statbuf, (char *)statP, sizeof(statbuf)); #endif /* API_32BIT */ if (rc != 0) { code = 5; goto xerror; } } xerror: if (releFile) fput(fP); TRACE2(TRACE_VNODE, 1, TRCID_LINUXOPS_TSFSTAT_EXIT, "tsfstat exit: code %d rc %d\n", code, rc); EXIT(0); return -rc; } int tsfattr(int fileDesc, int command, void *argP, tsfattrReasonCodeInfo *rCodeP) { struct gpfsVfsData_t *privVfsP; cxiNode_t *cnP; struct MMFSVInfo *vinfoP = NULL; ext_cred_t eCred; struct file *fP; struct inode *iP; int reason = 0; int code = 0; int flags; int rc; Boolean releFile = false; VFS_STAT_START(tsfattrCall); ENTER(0); #ifdef SMB_LOCKS_TEST /* hack to test setSMBOplock via tsfattr call */ if (command == 999) { int args[2]; int oplockGranted; struct file *fP; rc = cxiCopyIn((char *)argP, (char *)args, sizeof(args)); if (rc) return -rc; /* Obtain the file pointer from the descriptor */ fP = fget(fileDesc); if (!fP) return -EBADF; rc = setSMBOplock(fP, fP->private_data, args[0], args[1], (void *)0xdeadbeef, &oplockGranted, false); fput(fP); if (rc) return rc; return oplockGranted; } #endif /* if rCodeP was specified then immediately reset reason field */ if (rCodeP != NULL) { rc = cxiCopyOut((char*)&reason, (char*)&(rCodeP->reason), sizeof(reason)); if (rc != 0) { code = 1; goto xerror; } } fP = fget(fileDesc); if (!fP) { code = 2; rc = EBADF; goto xerror; } releFile = true; iP = fP->f_dentry->d_inode; DBGASSERT(iP != NULL); flags = cxiOpenFlagsXlate(fP->f_flags); TRACE8(TRACE_VNODE, 1, TRCID_LINUXOPS_TSFATTR_ENTER, "tsfattr enter: fd %d fP 0x%lX f_flags 0x%X flags 0x%X " "iP 0x%lX command %d argP 0x%lX rCodeP 0x%lX\n", fileDesc, fP, fP->f_flags, flags, iP, command, argP, rCodeP); switch (iP->i_mode & S_IFMT) { case S_IFREG: case S_IFDIR: vinfoP = (struct MMFSVInfo *)fP->private_data; break; case S_IFLNK: case S_IFBLK: case S_IFCHR: case S_IFIFO: case S_IFSOCK: /* At the moment we do have have any file ops enabled for the * special files on Linux, and thus we don't have an OpenFile object * or vinfoP stored in fP. This means that a special file can't * have e.g. ACLs associated with it. Fixing this properly will * require a redesign of our LFS interface. For now, just fix the * kernel panic caused by invalid vinfoP. */ vinfoP = NULL; if ((command != REMOTE_STAT) && // UIDREMAP (command != GET_XATTR) && // GPFS_LINUX (command != SET_XATTR)) // GPFS_LINUX { code = 5; rc = ENOSYS; goto xerror; } break; } if (!GPFS_TYPE(iP)) { code = 3; rc = EINVAL; goto xerror; } privVfsP = VP_TO_PVP(iP); if (privVfsP == NULL) { code = 4; rc = ENOENT; goto xerror; } cnP = VP_TO_CNP(iP); setCred(&eCred); rc = gpfs_ops.gpfsFattr(privVfsP, cnP, vinfoP, flags, command, argP, rCodeP, &eCred); xerror: if (releFile) fput(fP); TRACE2(TRACE_VNODE, 1, TRCID_LINUXOPS_TSFATTR_EXIT, "tsfattr exit: code %d rc %d\n", code, rc); VFS_STAT_STOP; EXIT(0); return -rc; } int tsfsattr(int command, void *argP) { int rc; VFS_STAT_START(tsfattrCall); ENTER(0); TRACE1(TRACE_VNODE, 1, TRCID_LINUXOPS_TSFSATTR_ENTER, "tsfsattr enter: command %s\n",tsfsattrcmd_id2name(command)); rc = gpfs_ops.gpfsFsAttr(command, argP); TRACE1(TRACE_VNODE, 1, TRCID_LINUXOPS_TSFSATTR_EXIT, "tsfsattr exit: rc %d\n", rc); VFS_STAT_STOP; EXIT(0); return -rc; } int tsattr(char *pathname, int command, void *argP, tsfattrReasonCodeInfo *rCodeP) { struct gpfsVfsData_t *privVfsP; cxiNode_t *cnP; int code = 0; int rc = 0; int reason = 0; /* local reason code for resetting caller's */ ext_cred_t eCred; struct nameidata nd; struct inode *iP; Boolean relePath = false; /* if rCodeP was specified then immediately reset reason field */ ENTER(0); if (rCodeP != NULL) { rc = cxiCopyOut((char*)&reason, (char*)&(rCodeP->reason), sizeof(reason)); if (rc != 0) { code = 1; goto xerror; } } rc = user_path_walk(pathname, &nd); if (rc) { rc = -rc; code = 2; goto xerror; } relePath = true; iP = nd.dentry->d_inode; DBGASSERT(iP != NULL); TRACE4(TRACE_VNODE, 1, TRCID_LINUXOPS_TSATTR_ENTER, "tsattr enter: iP 0x%lX command %d argP 0x%lX rCodeP 0x%lX\n", iP, command, argP, rCodeP); if (!GPFS_TYPE(iP)) { code = 3; rc = EINVAL; goto xerror; } privVfsP = VP_TO_PVP(iP); if (privVfsP == NULL) { code = 4; rc = ENOENT; goto xerror; } cnP = VP_TO_CNP(iP); setCred(&eCred); rc = gpfs_ops.gpfsFattr(privVfsP, cnP, NULL, 0, command, argP, rCodeP, &eCred); xerror: if (relePath) path_release(&nd); TRACE2(TRACE_VNODE, 1, TRCID_LINUXOPS_TSATTR_EXIT, "tsattr exit: code %d rc %d\n", code, rc); EXIT(0); return -rc; } int kxGetACL(char *pathname, int flags, void *aclP) { int rc = 0; int code = 0; cxiNode_t *cnP; struct gpfsVfsData_t *privVfsP; ext_cred_t eCred; struct nameidata nd; struct inode *iP; Boolean relePath = false; /* Verify input exists */ ENTER(0); if (pathname == NULL || aclP == NULL) { code = 1; rc = EINVAL; goto xerror; } rc = user_path_walk(pathname, &nd); if (rc) { rc = -rc; code = 2; goto xerror; } relePath = true; iP = nd.dentry->d_inode; DBGASSERT(iP != NULL); if (!GPFS_TYPE(iP)) { code = 3; rc = EINVAL; goto xerror; } privVfsP = VP_TO_PVP(iP); if (privVfsP == NULL) { code = 4; rc = ENOENT; goto xerror; } cnP = VP_TO_CNP(iP); /* Retrieve the ACL data */ setCred(&eCred); rc = gpfs_ops.gpfsGetAcl(privVfsP, cnP, flags, aclP, &eCred); xerror: if (relePath) path_release(&nd); TRACE2(TRACE_VNODE, 1, TRCID_LINUXOPS_KXGETACL_EXIT, "kxGetACL exit: code %d rc %d\n", code, rc); EXIT(0); return -rc; } int kxPutACL(char *pathname, int flags, void *aclP) { int rc = 0; int code = 0; cxiNode_t *cnP; struct gpfsVfsData_t *privVfsP; ext_cred_t eCred; struct nameidata nd; struct inode *iP; Boolean relePath = false; /* Verify input exists */ ENTER(0); if (pathname == NULL || aclP == NULL) { code = 1; rc = EINVAL; goto xerror; } rc = user_path_walk(pathname, &nd); if (rc) { rc = -rc; code = 2; goto xerror; } relePath = true; iP = nd.dentry->d_inode; DBGASSERT(iP != NULL); if (!GPFS_TYPE(iP)) { code = 3; rc = EINVAL; goto xerror; } privVfsP = VP_TO_PVP(iP); if (privVfsP == NULL) { code = 4; rc = ENOENT; goto xerror; } cnP = VP_TO_CNP(iP); /* Put the ACL data */ setCred(&eCred); rc = gpfs_ops.gpfsPutAcl(privVfsP, cnP, flags, aclP, &eCred); xerror: if (relePath) path_release(&nd); TRACE2(TRACE_VNODE, 1, TRCID_LINUXOPS_KXPUTACL_EXIT, "kxPutACL exit: code %d rc %d\n", code, rc); EXIT(0); return -rc; } #if !defined(GPFS_ARCH_X86_64) && !defined(GPFS_ARCH_IA64) /* madvise is handled as a kernel extension / ioctl call until support is provided by glibc */ //static inline _syscall3(int,madvise,void*,addr,size_t,len,int,advice); #endif int kxMadvise(void* addr, size_t len, int advice) { #if defined(GPFS_ARCH_X86_64) || defined(GPFS_ARCH_IA64) /* kxMadvise should never be called since glibc has madvice */ return -ENOSYS; #else // return madvise(addr, len, advice); // return stub_syscall2(__NR_madvise, len, advice); // return sys_madvise(addr, len, advice); return -ENOSYS; #endif } /* Get the kernel thread ID. */ cxiThreadId kxGetThreadID() { return (cxiThreadId)current->pid; } #ifdef GPFS_QUOTACTL int kxQuotactl(char *pathname, int cmd, int qid, void *bufferP) { int rc = 0; int code = 0; cxiNode_t *cnP; struct gpfsVfsData_t *privVfsP; ext_cred_t eCred; ext_cred_t *credP = NULL; struct nameidata nd; struct inode *iP; Boolean relePath = false; ulong len; ENTER(0); TRACE4(TRACE_VNODE, 2, TRCID_LINUXOPS_TSQUOTACTL_K, "kxQuotactl: enter cmd 0x%x, qid %d, pathname 0x%x, euid %d\n", cmd, qid, pathname, current->euid); /* Verify input exists */ if (pathname == NULL) { code = 1; // EBUF_ERROR rc = EINVAL; goto xerror; } TRACE0(TRACE_VNODE, 2, TRCID_LINUXOPS_TSQUOTACTL_K1, "kxQuotactl at [1]\n"); rc = user_path_walk(pathname, &nd); TRACE1(TRACE_VNODE, 2, TRCID_LINUXOPS_TSQUOTACTL_K2, "kxQuotactl at [2] user_path_walk rc %d\n", rc); if (rc) { rc = -rc; code = 3; goto xerror; } relePath = true; iP = nd.dentry->d_inode; DBGASSERT(iP != NULL); if (!GPFS_TYPE(iP)) { code = 3; rc = EINVAL; goto xerror; } privVfsP = VP_TO_PVP(iP); if (privVfsP == NULL) { code = 4; rc = ENOENT; goto xerror; } cnP = VP_TO_CNP(iP); setCred(&eCred); credP = &eCred; TRACE4(TRACE_VNODE, 2, TRCID_LINUXOPS_TSQUOTACTL_K6, "kxQuotactl: gpfs_ops.gpfsQuotactl, cmd 0x%x, qid %d, credP 0x%x, bufferP 0x%x\n", cmd, qid, credP, bufferP); rc = gpfs_ops.gpfsQuotactl(privVfsP, cmd, qid, bufferP, credP); TRACE1(TRACE_VNODE, 2, TRCID_LINUXOPS_TSQUOTACTL_K7, "kxQuotactl: gpfs_ops.gpfsQuotactl rc %d\n", rc); xerror: if (relePath) path_release(&nd); TRACE3(TRACE_VNODE, 1, TRCID_LINUXOPS_TSQUOTACTL_EXIT, "kxQuotactl exit: code %d rc %d, pathname %s\n", code, rc, pathname ? pathname : "?"); EXIT(0); return -rc; } #endif /* GPFS_QUOTACTL */ #ifdef SMB_LOCKS /* Exchange control between Samba, GPFS */ int setSMBOpenLockControl(void *vP, void *infoP, int command, int lockmode) { struct inode *iP; struct gpfsVfsData_t *privVfsP; struct MMFSVInfo *vinfoP; struct file *fP = (struct file *)vP; int rc = EINVAL; ENTER(0); TRACE2(TRACE_VNODE, 9, TRCID_SMBOPENLOCKCONTROL_ENTERL, "setSMBOpenLockControl entry - command %d, mode 0x%x", command, lockmode); vinfoP = (struct MMFSVInfo *)fP->private_data; iP = fP->f_dentry->d_inode; DBGASSERT(iP != NULL); if (!GPFS_TYPE(iP)) { rc = 0; goto xerror; } privVfsP = VP_TO_PVP(iP); rc = gpfs_ops.SMBOpenLockControl(command, lockmode, iP->i_ino, vinfoP, privVfsP); xerror: TRACE1(TRACE_VNODE, 1, TRCID_SMBOPENLOCKCONTROL_EXITL, "setSMBOpLockControl exit: rc %d\n", rc); EXIT(0); return (rc); } #include #include int setSMBOplock(void *vP, void *infoP, int accessWant, int oplockWant, void *breakArgP, int *oplockGrantedP, Boolean isAsync) { struct file *filp = (struct file *)vP; struct gpfsVfsData_t *privVfsP; cxiNode_t *cnP; struct MMFSVInfo *vinfoP; struct file *fP; struct inode *iP; int reason = 0; int code = 0; int flags; int rc; Boolean releFile = false; /* get file pointer and inode */ ENTER(0); fP = filp; if (!fP) { code = 2; rc = EBADF; goto xerror; } get_file(fP); releFile = true; vinfoP = (struct MMFSVInfo *)fP->private_data; iP = fP->f_dentry->d_inode; DBGASSERT(iP != NULL); TRACE5(TRACE_VNODE, 1, TRCID_LINUXOPS_SETSMBOPLOCK_E, "setSMBOplock enter: fP 0x%lX acc %d oplock %d argP 0x%lX async %d\n", fP, accessWant, oplockWant, breakArgP, isAsync); if (!GPFS_TYPE(iP)) { code = 3; rc = EINVAL; goto xerror; } privVfsP = VP_TO_PVP(iP); if (privVfsP == NULL) { code = 4; rc = ENOENT; goto xerror; } cnP = VP_TO_CNP(iP); rc = gpfs_ops.gpfsSetSMBOplock(privVfsP, cnP, vinfoP, accessWant, oplockWant, breakArgP, oplockGrantedP, isAsync); xerror: if (releFile) fput(fP); TRACE2(TRACE_VNODE, 1, TRCID_LINUXOPS_SETSMBOPLOCK_X, "setSMBOplock exit: granted %d rc %d", *oplockGrantedP, rc); EXIT(0); return -rc; } /* Share/Delegate interface for Samba */ int kxGetShare(int fd, unsigned int share, unsigned int deny) { int rc; struct file *fP = NULL; struct inode *iP; struct MMFSVInfo *vinfoP; struct gpfsVfsData_t *privVfsP; int shareWant; /* To be called from our Samba vfs_op library only. */ ENTER(0); if (!cxiIsSambaThread()) { rc = EPERM; goto xerror; } fP = fget(fd); if (!fP || !fP->f_dentry || !fP->f_dentry->d_inode) { rc = EINVAL; goto xerror; } vinfoP = (struct MMFSVInfo *)fP->private_data; iP = fP->f_dentry->d_inode; if (!iP || !(privVfsP = VP_TO_PVP(iP))) { rc = EBADF; goto xerror; } if (!GPFS_TYPE(iP)) { rc = 0; goto xerror; } shareWant = ALLOW_SHARE_DELETE; TRACE6(TRACE_VNODE, 1, TRCID_LINUX_SHARE_ENTER, "kxGetShare: enter fd %d fP 0x%lX ino %d infoP 0x%lX access 0x%X " "deny 0x%X\n", fd, fP, iP->i_ino, vinfoP, share, deny); /* Translate (and validate) the Samba share/deny arguments to our shareWant */ rc = EINVAL; /* setup for XLATE_SAMBA_ACCESS/DENY */ XLATE_SAMBA_ACCESS(share, shareWant); XLATE_SAMBA_DENY(deny, shareWant); /* Call to make the reservation */ if ((share != 0) || (deny != 0)) rc = gpfs_ops.gpfsReserveShare(fP, vinfoP, privVfsP, 0, shareWant, NULL,NULL); else rc = 0; /* give back any pre-existing rights */ if ((rc == 0) && (0 != (coMask & ~shareWant))) rc = gpfs_ops.gpfsReserveShare(fP, vinfoP, privVfsP, RESERVE_DOWNGRADE, coMask & ~shareWant, NULL, NULL); xerror: if (fP) fput(fP); TRACE1(TRACE_VNODE, 1, TRCID_LINUX_SHARE_EXIT, "kxGetShare: exit rc %d\n", rc); EXIT(0); return -rc; } int kxGetDelegation(int fd, unsigned int delegate_access, void *cb_token, void *cookie) { int rc = 0; int code = 0; int flags = 0; struct file *fP = NULL; struct inode *iP; struct MMFSVInfo *vinfoP; struct gpfsVfsData_t *privVfsP; int oplockWant; /* To be called from our Samba vfs_op library only. */ ENTER(0); if (!cxiIsSambaThread()) { rc = EPERM; goto xerror; } #if 0 /* As long as Samba write leases are not as strict as NFSv4 write delegations (are not required to be revoked on stat) we can allow them. */ if (delegate_access == CXI_DELEGATE_WRITE) { rc = EOPNOTSUPP; goto xerror; } #endif fP = fget(fd); if (!fP || !fP->f_dentry || !fP->f_dentry->d_inode) { rc = EINVAL; goto xerror; } vinfoP = (struct MMFSVInfo *)fP->private_data; iP = fP->f_dentry->d_inode; if (!iP || !(privVfsP = VP_TO_PVP(iP))) { rc = EBADF; goto xerror; } if (!GPFS_TYPE(iP)) { rc = 0; goto xerror; } TRACE5(TRACE_VNODE, 1, TRCID_DELEGATE_ENTER, "kxGetDelegation: enter fd %d fP 0x%lX ino %d vinfoP 0x%lX " "delegate 0x%x\n", fd, fP, iP->i_ino, vinfoP, delegate_access); /* Translate (and validate) the Samba delegate argument to our oplock flags */ /* setup for XLATE_SAMBA_DELEGATE */ rc = EINVAL; oplockWant = 0; if (delegate_access == CXI_DELEGATE_NONE) flags = RESERVE_DOWNGRADE; XLATE_SAMBA_DELEGATE(delegate_access, oplockWant); rc = gpfs_ops.gpfsReserveDelegation(fP, vinfoP, privVfsP, oplockWant, flags, iP, NULL); xerror: if (fP) fput(fP); TRACE1(TRACE_VNODE, 1, TRCID_DELEGATE_EXIT, "kxGetDelegation: exit rc %d\n", rc); EXIT(0); return -rc; } #endif /* called from umount helper before calling umount system call */ #define UMOUNT_BEGIN 0 #define UMOUNT_END 1 int kxUMount(int type, char *pathname, int force, int *ret_err) { char kxnode[CXI_MAXPATHLEN+1]; int rc = 0; int dmrc = 0; int code = 0; ulong len; struct cxiNode_t *cnP = NULL; struct gpfsVfsData_t *privVfsP = NULL; void *ndP = NULL; Boolean doDMEvents = false; ENTER(0); rc = cxiCopyInstr(pathname, kxnode, CXI_MAXPATHLEN, &len); LOGASSERT(rc == 0); TRACE4(TRACE_VNODE, 1, TRCID_KXUMOUNT_ENT, "kxUMount: enter type %d path %s force %d ret_err %d\n", type,kxnode,force,*ret_err); #ifdef DMAPI rc = cxiPathToVfsP((void **)&privVfsP,pathname, &ndP, (void **)&cnP, true); if (rc) { code = 1; goto exit; } /* Generate PREUNMOUNT event for normal mounts. For force unmount it is generated from gpfs_s_umount_begin. umount helper calls with UMOUNT_BEGIN before calling umount system call. */ if ( type == UMOUNT_BEGIN && !force) { dmrc = gpfs_ops.gpfsDmUnmountEvent(true,force,privVfsP,cnP, &doDMEvents, NULL, NULL, NULL, 0); if (doDMEvents ) *ret_err = 1; else *ret_err = 0; } /* umount helper calls with UMOUNT_END if umount system call fails. */ if ( type == UMOUNT_END ) dmrc = gpfs_ops.gpfsDmUnmountEvent(false,force,privVfsP,cnP, &doDMEvents, NULL, NULL, NULL, *ret_err); #endif exit: if (ndP) cxiPathRel(ndP); TRACE4(TRACE_VNODE, 1, TRCID_KXUMOUNT_EXT, "kxUMount: exit dmrc %d ret_err %d rc %d code %d\n", dmrc,*ret_err,rc,code); EXIT(0); return rc; }