[Libsysio-commit] HEAD: libsysio/src smp_posix.c access.c chdir.c chmod.c chown.c dup.c fcntl.c fil
Brought to you by:
lward
From: Lee W. <lw...@us...> - 2008-06-17 17:19:01
|
Update of /cvsroot/libsysio/libsysio/src In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv12543/src Modified Files: access.c chdir.c chmod.c chown.c dup.c fcntl.c file.c file_hack.c fs.c fsync.c getdirentries.c init.c inode.c ioctl.c ioctx.c link.c lseek.c mkdir.c mknod.c module.mk mount.c namei.c open.c readlink.c rename.c rmdir.c rw.c stat.c statvfs.c symlink.c truncate.c unlink.c utime.c Added Files: smp_posix.c Log Message: Begin adding support for thread-safe operation. In detail: 1) Add smp.h and smp_posix.c 2) Add a big lock, wrapping the user API with appropriate mutex_lock and mutex_unlock calls. NB; initialization is *not* thread safe. 3) Add support for P_{GET,LOCK}, PB_LOCK, I_{GET,LOCK}, FIL_{GET,LOCK} and alter all related ref/de-ref usage to use get/put or lock/unlock as appropriate. 4) Remedial (no-op) support for MNT_GET. By default, POSIX threads supoprt is not enabled. To enable, use --with-threads, or --with-threads=yes, or --with-threads=posix. --- NEW FILE --- /* * This Cplant(TM) source code is the property of Sandia National * Laboratories. * * This Cplant(TM) source code is copyrighted by Sandia National * Laboratories. * * The redistribution of this Cplant(TM) source code is subject to the * terms of the GNU Lesser General Public License * (see cit/LGPL or http://www.gnu.org/licenses/lgpl.html) * * Cplant(TM) Copyright 1998-2008 Sandia Corporation. * Under the terms of Contract DE-AC04-94AL85000, there is a non-exclusive * license for use of this work by or on behalf of the US Government. * Export of this program may require a license from the United States * Government. */ /* * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * Questions or comments about this library should be sent to: * * Lee Ward * Sandia National Laboratories, New Mexico * P.O. Box 5800 * Albuquerque, NM 87185-1319 * * le...@sa... */ #include "smp.h" int _posix_mutex_init_helper(mutex_t *mp, int typ) { pthread_mutexattr_t mattr; int err; if ((err = pthread_mutexattr_init(&mattr))) return err; if ((err = pthread_mutexattr_settype(&mattr, typ))) return err; err = pthread_mutex_init(mp, &mattr); return err; } Index: access.c =================================================================== RCS file: /cvsroot/libsysio/libsysio/src/access.c,v retrieving revision 1.18 retrieving revision 1.19 diff -u -w -b -B -p -r1.18 -r1.19 --- access.c 15 Apr 2008 19:29:06 -0000 1.18 +++ access.c 17 Jun 2008 17:18:57 -0000 1.19 @@ -43,6 +43,7 @@ #include <stdlib.h> #include <errno.h> +#include <assert.h> #include <unistd.h> #include <assert.h> #include <sys/types.h> @@ -286,7 +287,7 @@ SYSIO_INTERFACE_NAME(access)(const char err = _sysio_check_permission(pno, &cr, amode); out: - P_RELE(pno); + P_PUT(pno); SYSIO_INTERFACE_RETURN(err ? -1 : 0, err, access, "%d", 0); } Index: chdir.c =================================================================== RCS file: /cvsroot/libsysio/libsysio/src/chdir.c,v retrieving revision 1.32 retrieving revision 1.33 diff -u -w -b -B -p -r1.32 -r1.33 --- chdir.c 14 Apr 2008 23:22:47 -0000 1.32 +++ chdir.c 17 Jun 2008 17:18:57 -0000 1.33 @@ -114,6 +114,7 @@ _sysio_p_chdir(struct pnode *pno) /* * Finally, change to the new. */ + P_REF(pno); _sysio_cwd = pno; return 0; @@ -132,8 +133,7 @@ SYSIO_INTERFACE_NAME(chdir)(const char * SYSIO_INTERFACE_RETURN(-1, err, chdir, "%d", 0); err = _sysio_p_chdir(pno); - if (err) - P_RELE(pno); + P_PUT(pno); SYSIO_INTERFACE_RETURN(err ? -1 : 0, err, chdir, "%d", 0); } @@ -160,10 +160,11 @@ SYSIO_INTERFACE_NAME(getcwd)(char *buf, */ if (_sysio_namei(NULL, ".", 0, NULL, &pno) != 0) abort(); - P_RELE(pno); - } + } else #endif + P_GET(_sysio_cwd); err = _sysio_p_path(_sysio_cwd, &buf, buf ? size : 0); + P_PUT(_sysio_cwd); SYSIO_INTERFACE_RETURN(err ? NULL : buf, err, getcwd, "%s", 0); } Index: chmod.c =================================================================== RCS file: /cvsroot/libsysio/libsysio/src/chmod.c,v retrieving revision 1.20 retrieving revision 1.21 diff -u -w -b -B -p -r1.20 -r1.21 --- chmod.c 29 Feb 2008 23:14:34 -0000 1.20 +++ chmod.c 17 Jun 2008 17:18:57 -0000 1.21 @@ -83,7 +83,7 @@ SYSIO_INTERFACE_NAME(chmod)(const char * if (err) goto out; err = do_chmod(pno, mode); - P_RELE(pno); + P_PUT(pno); out: SYSIO_INTERFACE_RETURN(err ? -1 : 0, err, chmod, "%d", 0); } @@ -110,6 +110,7 @@ SYSIO_INTERFACE_NAME(fchmod)(int fd, mod } err = do_chmod(fil->f_pno, mode); + FIL_PUT(fil); out: SYSIO_INTERFACE_RETURN(err ? -1 : 0, err, fchmod, "%d", 0); } Index: chown.c =================================================================== RCS file: /cvsroot/libsysio/libsysio/src/chown.c,v retrieving revision 1.16 retrieving revision 1.17 diff -u -w -b -B -p -r1.16 -r1.17 --- chown.c 19 Sep 2007 16:01:33 -0000 1.16 +++ chown.c 17 Jun 2008 17:18:57 -0000 1.17 @@ -88,7 +88,7 @@ SYSIO_INTERFACE_NAME(chown)(const char * goto out; err = _do_chown(pno, owner, group); - P_RELE(pno); + P_PUT(pno); out: SYSIO_INTERFACE_RETURN(err ? -1 : 0, err, chown, "%d", 0); } @@ -115,6 +115,7 @@ SYSIO_INTERFACE_NAME(fchown)(int fd, uid } err = _do_chown(fil->f_pno, owner, group); + FIL_PUT(fil); out: SYSIO_INTERFACE_RETURN(err ? -1 : 0, err, fchown, "%d", 0); } Index: dup.c =================================================================== RCS file: /cvsroot/libsysio/libsysio/src/dup.c,v retrieving revision 1.14 retrieving revision 1.15 diff -u -w -b -B -p -r1.14 -r1.15 --- dup.c 2 Jul 2007 18:58:16 -0000 1.14 +++ dup.c 17 Jun 2008 17:18:57 -0000 1.15 @@ -44,9 +44,11 @@ #include <unistd.h> #include <errno.h> #include <sys/types.h> +#include <sys/stat.h> #include <sys/queue.h> #include "sysio.h" +#include "inode.h" #include "file.h" #include "sysio-symbols.h" Index: fcntl.c =================================================================== RCS file: /cvsroot/libsysio/libsysio/src/fcntl.c,v retrieving revision 1.30 retrieving revision 1.31 diff -u -w -b -B -p -r1.30 -r1.31 --- fcntl.c 2 Jul 2007 18:58:16 -0000 1.30 +++ fcntl.c 17 Jun 2008 17:18:57 -0000 1.31 @@ -269,6 +269,7 @@ _sysio_vfcntl(int fd, int cmd, va_list a } out: + FIL_PUT(fil); SYSIO_INTERFACE_RETURN(rtn, err, vfcntl, "%d", 0); } Index: file.c =================================================================== RCS file: /cvsroot/libsysio/libsysio/src/file.c,v retrieving revision 1.22 retrieving revision 1.23 diff -u -w -b -B -p -r1.22 -r1.23 --- file.c 1 May 2007 16:33:53 -0000 1.22 +++ file.c 17 Jun 2008 17:18:57 -0000 1.23 @@ -49,8 +49,10 @@ #include <sys/queue.h> #include "sysio.h" -#include "file.h" +#include "fs.h" +#include "mount.h" #include "inode.h" +#include "file.h" /* * Support for file IO. @@ -74,9 +76,10 @@ _sysio_fnew(struct pnode *pno, int flags if (!fil) return NULL; + P_REF(pno); _SYSIO_FINIT(fil, pno, flags); - F_REF(fil); - P_REF(fil->f_pno); + FIL_LOCK(fil); + FIL_REF(fil); return fil; } @@ -87,13 +90,43 @@ _sysio_fnew(struct pnode *pno, int flags void _sysio_fgone(struct file *fil) { - int err; + int oerr, err; assert(!fil->f_ref); assert(fil->f_pno); - err = PNOP_CLOSE(fil->f_pno); - assert(!err); + oerr = 0; + P_GET(fil->f_pno); + while ((err = PNOP_CLOSE(fil->f_pno))) { + if (err == EBADF) { + if (!oerr) + oerr = err; + break; + } else if (oerr) { + char *path; + static char *error_path = "<noname>"; + + /* + * If this happens we are bleeding file descriptors + * from somewhere. + */ + path = NULL; + if (_sysio_pb_pathof(fil->f_pno->p_base, + PATH_SEPARATOR, + &path) != 0) + path = error_path; + _sysio_cprintf("[lu]\"%s\" pnode won't close (%d)\n", + fil->f_pno->p_mount->mnt_fs->fs_id, + path); + if (path != error_path) + free(path); + break; + } + oerr = err; + } + P_PUT(fil->f_pno); P_RELE(fil->f_pno); + mutex_unlock(&fil->f_mutex); + mutex_destroy(&fil->f_mutex); free(fil); } @@ -193,10 +226,15 @@ find_free_fildes(int low) struct file * _sysio_fd_find(int fd) { + struct file *fil; + if (fd < 0 || (unsigned )fd >= _sysio_oftab_size) return NULL; - return _sysio_oftab[fd]; + fil = _sysio_oftab[fd]; + if (fil) + FIL_GET(fil); + return fil; } /* @@ -212,8 +250,8 @@ _sysio_fd_close(int fd) return -EBADF; _sysio_oftab[fd] = NULL; - - F_RELE(fil); + FIL_RELE(fil); + FIL_PUT(fil); return 0; } @@ -254,8 +292,11 @@ _sysio_fd_set(struct file *fil, int fd, * Take the entry. */ _sysio_oftab[fd] = fil; - if (ofil) - F_RELE(ofil); + FIL_REF(fil); + if (ofil) { + FIL_RELE(ofil); + FIL_PUT(ofil); + } return fd; } @@ -282,8 +323,7 @@ _sysio_fd_dup(int oldfd, int newfd, int return -EBADF; fd = _sysio_fd_set(fil, newfd, force); - if (fd >= 0) - F_REF(fil); + FIL_PUT(fil); return fd; } @@ -301,7 +341,10 @@ _sysio_fd_close_all() fd++, filp++) { if (!*filp) continue; - F_RELE(*filp); + FIL_LOCK(*filp); + P_RELE((*filp)->f_pno); + FIL_RELE(*filp); + FIL_UNLOCK(*filp); *filp = NULL; } Index: file_hack.c =================================================================== RCS file: /cvsroot/libsysio/libsysio/src/file_hack.c,v retrieving revision 1.12 retrieving revision 1.13 diff -u -w -b -B -p -r1.12 -r1.13 --- file_hack.c 1 May 2007 16:33:53 -0000 1.12 +++ file_hack.c 17 Jun 2008 17:18:57 -0000 1.13 @@ -105,9 +105,10 @@ _sysio_fnew(struct pnode *pno, int flags if (!fil) return NULL; - _SYSIO_FINIT(fil, pno, flags); - F_REF(fil); P_REF(pno); + _SYSIO_FINIT(fil, pno, flags); + FIL_LOCK(fil); + FIL_REF(fil); return fil; } @@ -118,16 +119,45 @@ _sysio_fnew(struct pnode *pno, int flags void _sysio_fgone(struct file *fil) { - int err; + int oerr, err; assert(!fil->f_ref); assert(fil->f_pno); - err = PNOP_CLOSE(fil->f_pno); + oerr = 0; + P_GET(fil->f_pno); + while ((err = PNOP_CLOSE(fil->f_pno))) { + if (err == EBADF) { + if (!oerr) + oerr = err; + break; + } else if (oerr) { + char *path; + static char *error_path = "<noname>"; + + /* + * If this happens we are bleeding file descriptors + * from somewhere. + */ + path = NULL; + if (_sysio_pb_pathof(fil->f_pno->p_base, + PATH_SEPARATOR, + &path) != 0) + path = error_path; + _sysio_cprintf("[lu]\"%s\" pnode won't close (%d)\n", + fil->f_pno->p_mount->mnt_fs->fs_id, + path); + if (path != error_path) + free(path); + break; + } + oerr = err; + } + P_PUT(fil->f_pno); P_RELE(fil->f_pno); - assert(!err); + mutex_unlock(&fil->f_mutex); + mutex_destroy(&fil->f_mutex); free(fil); } - /* * IO operation completion handler. */ @@ -244,7 +274,7 @@ find_free_fildes(oftab_t *oftab, int low * clear this entry if 'clear' is non-zero */ static struct file * -__sysio_fd_get(int fd, int clear) +_sysio_fd_get(int fd, int clear) { oftab_t *oftab; struct file *file; @@ -259,6 +289,8 @@ __sysio_fd_get(int fd, int clear) return NULL; file = oftab->table[fd - oftab->offset]; + if (file) + FIL_GET(file); if (clear) oftab->table[fd - oftab->offset] = NULL; @@ -271,7 +303,8 @@ __sysio_fd_get(int fd, int clear) struct file * _sysio_fd_find(int fd) { - return __sysio_fd_get(fd, 0); + + return _sysio_fd_get(fd, 0); } /* @@ -282,11 +315,11 @@ _sysio_fd_close(int fd) { struct file *fil; - fil = fil = __sysio_fd_get(fd, 1); + fil = _sysio_fd_get(fd, 1); if (!fil) return -EBADF; - - F_RELE(fil); + FIL_RELE(fil); + FIL_PUT(fil); return 0; } @@ -328,22 +361,17 @@ _sysio_fd_set(struct file *fil, int fd, /* * Remember old. */ - ofil = __sysio_fd_get(fd, 1); + ofil = _sysio_fd_get(fd, 1); + /* + * Take the entry. + */ + oftab->table[fd - oftab->offset] = fil; + FIL_REF(fil); if (ofil) { - /* FIXME sometimes we could intercept open/socket to create - * a fd, but missing close()? currently we have this problem - * with resolv lib. as a workaround simply destroy the file - * struct here. And this hack will break the behavior of - * DUPFD. - */ - if (fd >= 0 && oftab == &_sysio_oftab[0]) - free(ofil); - else - F_RELE(ofil); + FIL_RELE(ofil); + FIL_PUT(ofil); } - oftab->table[fd - oftab->offset] = fil; - return fd; } @@ -371,12 +399,12 @@ _sysio_fd_dup(int oldfd, int newfd, int return -EBADF; /* old & new must belong to the same oftab */ - if (select_oftab(oldfd) != select_oftab(newfd)) + if (select_oftab(oldfd) != select_oftab(newfd)) { + FIL_PUT(fil); return -EINVAL; + } fd = _sysio_fd_set(fil, newfd, force); - if (fd >= 0) - F_REF(fil); return fd; } @@ -391,7 +419,10 @@ _sysio_oftable_close_all(oftab_t *oftab) fd++, filp++) { if (!*filp) continue; - F_RELE(*filp); + FIL_LOCK(*filp); + P_RELE((*filp)->f_pno); + FIL_RELE(*filp); + FIL_UNLOCK(*filp); *filp = NULL; } } Index: fs.c =================================================================== RCS file: /cvsroot/libsysio/libsysio/src/fs.c,v retrieving revision 1.15 retrieving revision 1.16 diff -u -w -b -B -p -r1.15 -r1.16 --- fs.c 1 May 2007 16:33:53 -0000 1.15 +++ fs.c 17 Jun 2008 17:18:57 -0000 1.16 @@ -145,14 +145,17 @@ _sysio_fs_gone(struct filesys *fs) { size_t n; struct itable_entry *head; + struct inode *ino; if (fs->fs_ref) abort(); n = FS_ITBLSIZ; do { head = &fs->fs_itbl[--n]; - while (head->lh_first) - _sysio_i_gone(head->lh_first); + while ((ino = head->lh_first)) { + I_LOCK(ino); + I_GONE(ino); + } } while (n); if (n) abort(); Index: fsync.c =================================================================== RCS file: /cvsroot/libsysio/libsysio/src/fsync.c,v retrieving revision 1.11 retrieving revision 1.12 diff -u -w -b -B -p -r1.11 -r1.12 --- fsync.c 20 Nov 2007 17:46:28 -0000 1.11 +++ fsync.c 17 Jun 2008 17:18:57 -0000 1.12 @@ -43,6 +43,7 @@ #include <unistd.h> #include <errno.h> +#include <assert.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> @@ -63,11 +64,12 @@ SYSIO_INTERFACE_NAME(fsync)(int fd) err = 0; do { fil = _sysio_fd_find(fd); - if (!F_FILEOK(fil)) + if (!FIL_FILEOK(fil)) err = -EBADF; if (err) break; err = PNOP_SYNC(fil->f_pno); + FIL_PUT(fil); } while (0); SYSIO_INTERFACE_RETURN(err ? -1 : 0, err, fsync, "%d", 0); } @@ -83,11 +85,12 @@ SYSIO_INTERFACE_NAME(fdatasync)(int fd) err = 0; do { fil = _sysio_fd_find(fd); - if (!F_FILEOK(fil)) + if (!FIL_FILEOK(fil)) err = -EBADF; if (err) break; err = PNOP_DATASYNC(fil->f_pno); + FIL_PUT(fil); } while (0); SYSIO_INTERFACE_RETURN(err ? -1 : 0, err, fdatasync, "%d", 0); } Index: getdirentries.c =================================================================== RCS file: /cvsroot/libsysio/libsysio/src/getdirentries.c,v retrieving revision 1.26 retrieving revision 1.27 diff -u -w -b -B -p -r1.26 -r1.27 --- getdirentries.c 15 Nov 2007 15:05:34 -0000 1.26 +++ getdirentries.c 17 Jun 2008 17:18:57 -0000 1.27 @@ -48,6 +48,7 @@ #endif #include <string.h> #include <errno.h> +#include <assert.h> #include <sys/types.h> #include <sys/stat.h> #include <dirent.h> @@ -99,8 +100,13 @@ PREPEND(_, SYSIO_INTERFACE_NAME(getdiren SYSIO_INTERFACE_ENTER(getdirentries64, "%d%zu%oZ", fd, nbytes, basep); + cc = -EBADF; /* assume failure */ fil = _sysio_fd_find(fd); + if (FIL_FILEOK(fil)) { cc = filldirents(fil, buf, nbytes, basep); + FIL_PUT(fil); + } + SYSIO_INTERFACE_RETURN(cc < 0 ? -1 : cc, cc < 0 ? (int )cc : 0, getdirentries64, "%zd%oZ", basep); @@ -167,8 +173,13 @@ SYSIO_INTERFACE_NAME(getdirentries)(int SYSIO_INTERFACE_ENTER(getdirentries, "%d%zu%d", fd, nbytes, *basep); + cc = -EBADF; /* assume failure */ fil = _sysio_fd_find(fd); - count = cc = filldirents(fil, buf, nbytes, &b); + if (FIL_FILEOK(fil)) { + cc = filldirents(fil, buf, nbytes, &b); + FIL_PUT(fil); + } + count = cc; d64p = (void *)buf; dp = (void *)buf; reclen = 0; @@ -224,24 +235,18 @@ SYSIO_INTERFACE_NAME(getdirentries)(int d64p = (struct dirent64 *)((char *)d64p + d64.d_reclen); } - if (cc < 0) { #ifndef BSD #define _basefmt "%oY" #else #define _basefmt "%ld" #endif + if (cc < 0) { SYSIO_INTERFACE_RETURN(-1, cc, getdirentries, "%zd" _basefmt, *basep); -#undef _basefmt } cc = (char *)dp - buf; *basep = b; -#ifndef BSD -#define _basefmt "%oY" -#else -#define _basefmt "%ld" -#endif SYSIO_INTERFACE_RETURN(cc, 0, getdirentries, "%zd" _basefmt, *basep); #undef _basefmt } Index: init.c =================================================================== RCS file: /cvsroot/libsysio/libsysio/src/init.c,v retrieving revision 1.40 retrieving revision 1.41 diff -u -w -b -B -p -r1.40 -r1.41 --- init.c 17 Jun 2008 15:11:40 -0000 1.40 +++ init.c 17 Jun 2008 17:18:57 -0000 1.41 @@ -66,6 +66,8 @@ #include "stddev.h" #endif +mutex_t _sysio_biglock; /* API big lock */ + /* * White space characters. */ @@ -194,6 +196,8 @@ _sysio_init() extern int _sysio_sockets_init(void); #endif + mutex_init(&_sysio_biglock, MUTEX_RECURSIVE); + #ifdef SYSIO_TRACING err = _sysio_trace_init(); if (err) @@ -266,6 +270,8 @@ _sysio_shutdown() _sysio_fssw_shutdown(); _sysio_access_shutdown(); #endif + + mutex_destroy(&_sysio_biglock); } /* @@ -552,7 +558,7 @@ do_creat(char *args) abort(); } - P_RELE(pno); + P_PUT(pno); return err; } @@ -607,12 +613,14 @@ do_mnt(char *args) if (!(dir = _sysio_cwd) && !(dir = _sysio_root)) return -ENOENT; + P_GET(dir); return _sysio_mount(dir, ty, v[1].ovi_value, name, flags, v[3].ovi_value); + P_PUT(dir); } @@ -648,8 +656,7 @@ do_cd(char *args) if (err) return err; err = _sysio_p_chdir(pno); - if (err) - P_RELE(pno); + P_PUT(pno); return err; } #endif @@ -693,7 +700,7 @@ do_chmd(char *args) if (err) return err; err = _sysio_p_setattr(pno, SETATTR_MODE, &stbuf); - P_RELE(pno); + P_PUT(pno); return err; } @@ -756,9 +763,9 @@ do_open(char *args) return 0; } while (0); if (fil) - F_RELE(fil); + FIL_PUT(fil); if (pno) - P_RELE(pno); + P_PUT(pno); return err; } Index: inode.c =================================================================== RCS file: /cvsroot/libsysio/libsysio/src/inode.c,v retrieving revision 1.42 retrieving revision 1.43 diff -u -w -b -B -p -r1.42 -r1.43 --- inode.c 23 Apr 2008 16:46:40 -0000 1.42 +++ inode.c 17 Jun 2008 17:18:57 -0000 1.43 @@ -226,8 +226,8 @@ _sysio_i_new(struct filesys *fs, void *private) { struct inode *ino; - struct itable_entry *head; struct inode_ops operations; + struct itable_entry *head; if (n_inodes > n_names) { /* @@ -241,7 +241,6 @@ _sysio_i_new(struct filesys *fs, ino = malloc(sizeof(struct inode)); if (!ino) return NULL; - ino->i_ops = *ops; operations = *ops; if (S_ISBLK(stat->st_mode) || S_ISCHR(stat->st_mode) || @@ -269,6 +268,9 @@ _sysio_i_new(struct filesys *fs, head = &fs->fs_itbl[hash(fid) % FS_ITBLSIZ]; LIST_INSERT_HEAD(head, ino, i_link); + I_GET(ino); + I_RELE(ino); + n_inodes++; assert(n_inodes); @@ -294,7 +296,7 @@ _sysio_i_find(struct filesys *fs, struct memcmp(ino->i_fid->fid_data, fid->fid_data, fid->fid_len) == 0) { - I_REF(ino); + I_GET(ino); INO_CST_UPDCNT(ihits); break; } @@ -316,6 +318,8 @@ _sysio_i_gone(struct inode *ino) LIST_REMOVE(ino, i_link); TAILQ_REMOVE(&_sysio_inodes, ino, i_nodes); (*ino->i_ops.inop_gone)(ino); + I_UNLOCK(ino); + mutex_destroy(&ino->i_mutex); free(ino); assert(n_inodes); @@ -389,6 +393,7 @@ p_reclaim(unsigned count) do { INO_CST_UPDCNT(pexamined); pno = next; + P_LOCK(pno); next = pno->p_idle.tqe_next; if (pno->p_ref) abort(); @@ -396,6 +401,7 @@ p_reclaim(unsigned count) /* * We never reclaim mount points, here. */ + P_UNLOCK(pno); continue; } if (pno->p_base->pb_children.lh_first) { @@ -404,13 +410,17 @@ p_reclaim(unsigned count) * might be aliases on the child pointing * at this one. */ + P_UNLOCK(pno); continue; } INO_CST_UPDCNT(pdismissed); + PB_LOCK(pno->p_base); pb = pno->p_base; _sysio_p_gone(pno); if (!(pb->pb_children.lh_first || pb->pb_aliases.lh_first)) _sysio_pb_gone(pb); + else + PB_UNLOCK(pb); } while ((!count || --count) && n_names > t && next); if (!adjust) @@ -503,6 +513,7 @@ struct pnode_base * _sysio_pb_new(struct qstr *name, struct pnode_base *parent, struct inode *ino) { struct pnode_base *pb; + static struct qstr noname = { NULL, 0, 0 }; if (n_names > max_names) { /* @@ -515,13 +526,17 @@ _sysio_pb_new(struct qstr *name, struct if (!pb) return NULL; - pb->pb_key.pbk_name = *name; - pb->pb_key.pbk_parent = parent; + if (!name) + name = &noname; + PB_INIT(pb, name, parent, ino); + if (ino) + I_REF(ino); + PB_GET(pb); + if (parent) + LIST_INSERT_HEAD(&parent->pb_children, pb, pb_sibs); if (pb->pb_key.pbk_name.len) { char *cp; - pb->pb_tentry.tn_key = &pb->pb_key; - pb->pb_tentry.tn_left = pb->pb_tentry.tn_right = NULL; /* * Copy the passed name. * @@ -531,15 +546,9 @@ _sysio_pb_new(struct qstr *name, struct cp = (char *)pb + sizeof(struct pnode_base); (void )strncpy(cp, name->name, name->len); pb->pb_key.pbk_name.name = cp; - pb->pb_key.pbk_name.hashval = name->hashval; ncache_insert(pb); } - pb->pb_ino = ino; - LIST_INIT(&pb->pb_children); - LIST_INIT(&pb->pb_aliases); - if (parent) - LIST_INSERT_HEAD(&parent->pb_children, pb, pb_sibs); #ifdef P_RECLAIM_DEBUG LIST_INSERT_HEAD(&pbnodes, pb, pb_links); #endif @@ -551,20 +560,19 @@ _sysio_pb_new(struct qstr *name, struct } /* - * Destroy base path node, releasing resources back to the system. - * - * NB: Caller must release the inode referenced by the record. + * Force reclaim of idle base path node. */ -static void -pb_destroy(struct pnode_base *pb) +void +_sysio_pb_gone(struct pnode_base *pb) { + struct inode *ino; assert(n_names); n_names--; assert(!pb->pb_aliases.lh_first); assert(!pb->pb_children.lh_first); - assert(!pb->pb_ino); + if (pb->pb_key.pbk_name.len) ncache_delete(pb); if (pb->pb_key.pbk_parent) @@ -572,25 +580,21 @@ pb_destroy(struct pnode_base *pb) #ifdef P_RECLAIM_DEBUG LIST_REMOVE(pb, pb_links); #endif - + ino = pb->pb_ino; + if (ino) + I_LOCK(ino); + pb->pb_ino = NULL; + PB_UNLOCK(pb); + mutex_destroy(&pb->pb_mutex); free(pb); -} - -/* - * Force reclaim of idle base path node. - */ -void -_sysio_pb_gone(struct pnode_base *pb) -{ - if (pb->pb_ino) { - I_RELE(pb->pb_ino); - if (!pb->pb_ino->i_ref) - _sysio_i_gone(pb->pb_ino); + if (ino) { + I_RELE(ino); + if (!ino->i_ref) + _sysio_i_gone(ino); + else + I_UNLOCK(ino); } - pb->pb_ino = NULL; - - pb_destroy(pb); } /* @@ -751,13 +755,12 @@ _sysio_p_new_alias(struct pnode *parent, if (!pno) return NULL; + if (!parent) + parent = pno; + P_INIT(pno, parent, pb, mnt, NULL); pno->p_ref = 1; - pno->p_parent = parent; - if (!pno->p_parent) - pno->p_parent = pno; - pno->p_base = pb; - pno->p_mount = mnt; - pno->p_cover = NULL; + P_GET(pno); + P_RELE(pno); LIST_INSERT_HEAD(&pb->pb_aliases, pno, p_links); #ifdef P_DEBUG _sysio_p_show("P_CREATE_ALIAS", pno); @@ -863,6 +866,8 @@ _sysio_p_gone(struct pnode *pno) #ifdef P_DEBUG _sysio_p_show("P_GONE", pno); #endif + P_UNLOCK(pno); + mutex_destroy(&pno->p_mutex); free(pno); } @@ -886,13 +891,14 @@ _sysio_p_validate(struct pnode *pno, str * Make valid. */ pno->p_base->pb_ino = ino; + I_REF(pno->p_base->pb_ino); } else if (pno->p_base->pb_ino != ino) { /* * Path resolves to a different inode, now. The * currently attached inode, then, is stale. */ err = -ESTALE; - I_RELE(ino); + I_PUT(ino); } } else if (pno->p_base->pb_ino) _sysio_pb_disconnect(pno->p_base); @@ -931,9 +937,11 @@ _sysio_p_find_alias(struct pnode *parent key.pbk_name = *name; key.pbk_parent = parent->p_base; pb = ncache_lookup(&key); - if (pb) + if (pb) { + PB_GET(pb); INO_CST_UPDCNT(pbhits); } + } if (!pb) { /* * None found, create new child. @@ -950,7 +958,7 @@ _sysio_p_find_alias(struct pnode *parent pno = pb->pb_aliases.lh_first; while (pno) { if (pno->p_parent == parent) { - P_REF(pno); + P_GET(pno); break; } pno = pno->p_links.le_next; @@ -969,6 +977,7 @@ _sysio_p_find_alias(struct pnode *parent if (!pno) err = -ENOMEM; } + PB_PUT(pb); if (!err) { #ifdef P_DEBUG if (!isnew) @@ -1012,8 +1021,15 @@ p_remove_aliases(struct mount *mnt, stru struct pnode *nxtpno, *pno; count = 0; + pno = NULL; nxtpno = pb->pb_aliases.lh_first; - while ((pno = nxtpno)) { + for (;;) { + if (pno) + P_UNLOCK(pno); + pno = nxtpno; + if (!pno) + break; + P_LOCK(pno); nxtpno = pno->p_links.le_next; if (pno->p_mount != mnt) { /* @@ -1042,6 +1058,7 @@ p_remove_aliases(struct mount *mnt, stru } #endif _sysio_p_gone(pno); + pno = NULL; } return count; @@ -1053,6 +1070,7 @@ pb_prune(struct mount *mnt, struct pnode size_t count; struct pnode_base *nxt, *child; + PB_LOCK(pb); count = 0; nxt = pb->pb_children.lh_first; while ((child = nxt)) { @@ -1061,9 +1079,13 @@ pb_prune(struct mount *mnt, struct pnode } if (!count) { count += p_remove_aliases(mnt, pb); - if (!(pb->pb_aliases.lh_first || pb->pb_children.lh_first)) + if (!(pb->pb_aliases.lh_first || pb->pb_children.lh_first)) { _sysio_pb_gone(pb); + pb = NULL; + } } + if (pb) + PB_UNLOCK(pb); return count; } @@ -1080,6 +1102,78 @@ _sysio_p_prune(struct pnode *pno) } /* + * Simultaneous get of two path nodes. + */ +void +_sysio_p_get2(struct pnode *pno1, struct pnode *pno2) +{ + struct inode *ino1, *ino2; + char *cp1, *cp2; + size_t count1, count2; + int order; + + if (pno1 < pno2) { + P_LOCK(pno1); + P_LOCK(pno2); + } else { + P_LOCK(pno2); + P_LOCK(pno1); + } + if (pno1->p_base < pno2->p_base) { + PB_LOCK(pno1->p_base); + PB_LOCK(pno2->p_base); + } else { + PB_LOCK(pno2->p_base); + PB_LOCK(pno1->p_base); + } + /* + * File identifiers are never allowed to change and we've prevented + * the inode pointer from changing in the path-base records. So... + * It's safe to examine the file identifiers without a lock now. + */ + ino1 = pno1->p_base->pb_ino; + ino2 = pno2->p_base->pb_ino; + cp1 = NULL; + count1 = 0; + if (ino1) { + cp1 = ino1->i_fid->fid_data; + count1 = ino1->i_fid->fid_len; + } + cp2 = NULL; + count2 = 0; + if (ino2) { + cp2 = ino2->i_fid->fid_data; + count2 = ino2->i_fid->fid_len; + } + order = 0; + while (count1 && count2 && *cp1 == *cp2) { + cp1++; cp2++; + count1--; count2--; + } + if (count1 && count2) + order = *cp2 - *cp1; + else if (count1 > count2) + order = 1; + else if (count1 > count2) + order = -1; + if (order <= 0) { + P_GET(pno1); + P_GET(pno2); + } else { + P_GET(pno2); + P_GET(pno1); + } + /* + * We did get operations, finally, above. Have to release our + * redundant locks. The order in which we unlock is unimportant. + */ + PB_UNLOCK(pno1->p_base); + PB_UNLOCK(pno2->p_base); + P_UNLOCK(pno1); + P_UNLOCK(pno2); +} + +/* * Return path tracked by the base path node ancestor chain. * * Remember, base path nodes track the path relative to the file system and Index: ioctl.c =================================================================== RCS file: /cvsroot/libsysio/libsysio/src/ioctl.c,v retrieving revision 1.14 retrieving revision 1.15 diff -u -w -b -B -p -r1.14 -r1.15 --- ioctl.c 2 Jul 2007 18:58:16 -0000 1.14 +++ ioctl.c 17 Jun 2008 17:18:57 -0000 1.15 @@ -42,6 +42,7 @@ */ #include <errno.h> +#include <assert.h> #include <sys/ioctl.h> #include <sys/types.h> #include <sys/stat.h> @@ -72,6 +73,7 @@ SYSIO_INTERFACE_NAME(ioctl)(int fd, unsi va_start(ap, request); err = PNOP_IOCTL(fil->f_pno, request, ap); va_end(ap); + FIL_PUT(fil); out: SYSIO_INTERFACE_RETURN(err ? -1 : 0, err, ioctl, "%d%lu", request); Index: ioctx.c =================================================================== RCS file: /cvsroot/libsysio/libsysio/src/ioctx.c,v retrieving revision 1.27 retrieving revision 1.28 diff -u -w -b -B -p -r1.27 -r1.28 --- ioctx.c 14 May 2007 20:43:28 -0000 1.27 +++ ioctx.c 17 Jun 2008 17:18:57 -0000 1.28 @@ -110,6 +110,8 @@ _sysio_ioctx_new(struct pnode *pno, { struct ioctx *ioctx; + assert(pno->p_base->pb_ino); + ioctx = malloc(sizeof(struct ioctx)); if (!ioctx) return NULL; @@ -189,14 +191,17 @@ _sysio_ioctx_done(struct ioctx *ioctx) if (ioctx->ioctx_done) return 1; #ifdef not_yet - if (!PNOP_IODONE(ioctx->ioctx_pno, ioctx)) - return 0; + P_GET(ioctx->ioctx_pno); + if (PNOP_IODONE(ioctx->ioctx_pno, ioctx)) + ioctx->ioctx_done = 1; + P_PUT(ioctx->ioctx_pno); #else - if (!(*ioctx->ioctx_ino->i_ops.inop_iodone)(ioctx)) - return 0; -#endif + I_GET(ioctx->ioctx_ino); + if ((*ioctx->ioctx_ino->i_ops.inop_iodone)(ioctx)) ioctx->ioctx_done = 1; - return 1; + I_PUT(ioctx->ioctx_ino); +#endif + return (int )ioctx->ioctx_done; } /* Index: link.c =================================================================== RCS file: /cvsroot/libsysio/libsysio/src/link.c,v retrieving revision 1.15 retrieving revision 1.16 diff -u -w -b -B -p -r1.15 -r1.16 --- link.c 20 Nov 2007 17:49:26 -0000 1.15 +++ link.c 17 Jun 2008 17:18:57 -0000 1.16 @@ -71,12 +71,23 @@ SYSIO_INTERFACE_NAME(link)(const char *o _sysio_namei(_sysio_cwd, oldpath, 0, &intent, &old); if (err) break; + P_REF(old); + P_PUT(old); INTENT_INIT(&intent, INT_UPDPARENT, NULL, NULL); err = _sysio_namei(_sysio_cwd, newpath, ND_NEGOK, &intent, &new); if (err) break; + P_REF(new); + P_PUT(new); + if (new->p_base->pb_ino) { + err = -EEXIST; + break; + } + _sysio_p_get2(old, new->p_parent); err = _sysio_p_link(old, new); + P_PUT(new->p_parent); + P_PUT(old); } while (0); if (new) P_RELE(new); Index: lseek.c =================================================================== RCS file: /cvsroot/libsysio/libsysio/src/lseek.c,v retrieving revision 1.31 retrieving revision 1.32 diff -u -w -b -B -p -r1.31 -r1.32 --- lseek.c 19 Sep 2007 16:01:33 -0000 1.31 +++ lseek.c 17 Jun 2008 17:18:57 -0000 1.32 @@ -135,6 +135,7 @@ SYSIO_INTERFACE_NAME(lseek64)(int fd, of -EBADF, lseek64, "%loZ", 0); off = _sysio_lseek(fil, offset, whence, _SEEK_MAX(fil)); + FIL_PUT(fil); SYSIO_INTERFACE_RETURN(off < 0 ? (off64_t )-1 : off, off < 0 ? (int )off : 0, lseek64, "%loZ", 0); @@ -167,6 +168,7 @@ SYSIO_INTERFACE_NAME(lseek)(int fd, off_ if (!fil) SYSIO_INTERFACE_RETURN((off_t )-1, -EBADF, lseek, "%oZ", 0); off = _sysio_lseek(fil, offset, whence, LONG_MAX); + FIL_PUT(fil); if (off < 0) SYSIO_INTERFACE_RETURN((off_t )-1, (int )off, lseek, "%oZ", 0); rtn = (off_t )off; @@ -218,6 +220,7 @@ SYSIO_INTERFACE_NAME(llseek)(unsigned in off |= offset_low; #endif off = _sysio_lseek(fil, off, whence, _SEEK_MAX(fil)); + FIL_PUT(fil); if (off < 0) SYSIO_INTERFACE_RETURN(-1, (int )off, llseek, "%d", NULL); *result = off; Index: mkdir.c =================================================================== RCS file: /cvsroot/libsysio/libsysio/src/mkdir.c,v retrieving revision 1.23 retrieving revision 1.24 diff -u -w -b -B -p -r1.23 -r1.24 --- mkdir.c 27 Sep 2007 17:22:36 -0000 1.23 +++ mkdir.c 17 Jun 2008 17:18:57 -0000 1.24 @@ -86,7 +86,7 @@ SYSIO_INTERFACE_NAME(mkdir)(const char * mode &= ~(_sysio_umask & 0777); /* apply umask */ err = _sysio_mkdir(pno, mode); - P_RELE(pno); + P_PUT(pno); out: SYSIO_INTERFACE_RETURN(err ? -1 : 0, err, mkdir, "%d", 0); } Index: mknod.c =================================================================== RCS file: /cvsroot/libsysio/libsysio/src/mknod.c,v retrieving revision 1.22 retrieving revision 1.23 diff -u -w -b -B -p -r1.22 -r1.23 --- mknod.c 26 Oct 2007 19:48:23 -0000 1.22 +++ mknod.c 17 Jun 2008 17:18:57 -0000 1.23 @@ -109,7 +109,7 @@ PREPEND(__, SYSIO_INTERFACE_NAME(xmknod) goto error; err = _sysio_mknod(pno, mode, *dev); error: - P_RELE(pno); + P_PUT(pno); out: SYSIO_INTERFACE_RETURN(err ? -1 : 0, err, xmknod, "%d", 0); } Index: module.mk =================================================================== RCS file: /cvsroot/libsysio/libsysio/src/module.mk,v retrieving revision 1.16 retrieving revision 1.17 diff -u -w -b -B -p -r1.16 -r1.17 --- module.mk 21 Sep 2007 19:35:53 -0000 1.16 +++ module.mk 17 Jun 2008 17:18:57 -0000 1.17 @@ -1,3 +1,9 @@ +if WITH_THREAD_MODEL_POSIX +THREAD_MODEL_POSIX_SRCS = src/smp_posix.c +else +THREAD_MODEL_POSIX_SRCS = +endif + if WITH_TRACING TRACING_SRCS = src/tracing.c else @@ -30,7 +36,7 @@ SRCDIR_SRCS = src/access.c src/chdir.c s src/link.c src/lseek.c src/mkdir.c \ src/mknod.c src/mount.c src/namei.c \ src/open.c src/rw.c src/reconcile.c src/rename.c \ - src/rmdir.c src/stat.c $(STATVFS_SRCS) \ + src/rmdir.c $(THREAD_MODEL_POSIX_SRCS) src/stat.c $(STATVFS_SRCS) \ src/stddir.c src/readdir.c src/readdir64.c \ src/symlink.c src/readlink.c \ src/truncate.c src/unlink.c src/utime.c \ Index: mount.c =================================================================== RCS file: /cvsroot/libsysio/libsysio/src/mount.c,v retrieving revision 1.29 retrieving revision 1.30 diff -u -w -b -B -p -r1.29 -r1.30 --- mount.c 23 Apr 2008 00:23:21 -0000 1.29 +++ mount.c 17 Jun 2008 17:18:57 -0000 1.30 @@ -1,4 +1,5 @@ /* +P_REF(mnt->mnt_covers); * This Cplant(TM) source code is the property of Sandia National * Laboratories. * @@ -126,7 +127,7 @@ _sysio_do_mount(struct filesys *fs, * Directories only, please. */ if ((tocover && - !(tocover->p_base->pb_ino && + (tocover->p_base->pb_ino && S_ISDIR(tocover->p_base->pb_ino->i_stbuf.st_mode))) || !rootpb->pb_ino || !S_ISDIR(rootpb->pb_ino->i_stbuf.st_mode)) return -ENOTDIR; @@ -176,6 +177,12 @@ _sysio_do_mount(struct filesys *fs, goto error; } /* + * Need ref for the mount record but drop the locks now. + */ + P_REF(mnt->mnt_root); + P_PUT(mnt->mnt_root); + + /* * Cover up the mount point. */ mnt->mnt_covers = tocover; @@ -185,6 +192,7 @@ _sysio_do_mount(struct filesys *fs, */ mnt->mnt_covers = tocover = mnt->mnt_root; } + P_REF(mnt->mnt_covers); assert(!tocover->p_cover); tocover->p_cover = mnt->mnt_root; @@ -221,6 +229,8 @@ _sysio_mounti(struct filesys *fs, err = _sysio_do_mount(fs, rootpb, flags, tocover, mntp); if (err) _sysio_pb_gone(rootpb); + else + PB_PUT(rootpb); return err; } @@ -235,11 +245,13 @@ _sysio_do_unmount(struct mount *mnt) struct filesys *fs; root = mnt->mnt_root; + P_LOCK(root); assert(root->p_ref); if (root->p_cover && root->p_cover != root) { /* * Active mount. */ + P_UNLOCK(root); return -EBUSY; } #ifdef P_DEBUG @@ -250,6 +262,7 @@ _sysio_do_unmount(struct mount *mnt) /* * Active aliases. */ + P_UNLOCK(root); return -EBUSY; } /* @@ -257,7 +270,6 @@ _sysio_do_unmount(struct mount *mnt) * * Drop ref of covered pnode and break linkage in name space. */ - if (root->p_cover != root) P_RELE(mnt->mnt_covers); mnt->mnt_covers->p_cover = NULL; LIST_REMOVE(mnt, mnt_link); @@ -267,9 +279,12 @@ _sysio_do_unmount(struct mount *mnt) P_RELE(root); root->p_cover = NULL; rootpb = root->p_base; + PB_LOCK(rootpb); _sysio_p_gone(root); if (!(rootpb->pb_aliases.lh_first || rootpb->pb_children.lh_first)) _sysio_pb_gone(rootpb); + else + PB_UNLOCK(rootpb); /* * Release mount record resource. */ @@ -281,6 +296,33 @@ _sysio_do_unmount(struct mount *mnt) } /* + * Helper function to find FS type and call FS-specific mount routine. + */ +static int +_sysio_fs_mount(const char *source, + const char *fstype, + unsigned status, + unsigned flags, + const void *data, + struct pnode *tocover, + struct mount **mntp) +{ + struct fsswent *fssw; + int err; + + assert(((status & MOUNT_ST_IFST) == status) && + !(flags & MOUNT_ST_IFST)); + flags |= status & MOUNT_ST_IFST; + fssw = _sysio_fssw_lookup(fstype); + if (!fssw) + return -ENODEV; + assert(fssw->fssw_ops.fsswop_mount); + err = + (*fssw->fssw_ops.fsswop_mount)(source, flags, data, tocover, mntp); + return err; +} + +/* * Establish the system name space. */ int @@ -289,22 +331,19 @@ _sysio_mount_root(const char *source, unsigned flags, const void *data) { - struct fsswent *fssw; int err; struct mount *mnt; if (_sysio_root) return -EBUSY; - fssw = _sysio_fssw_lookup(fstype); - if (!fssw) - return -ENODEV; - - err = (*fssw->fssw_ops.fsswop_mount)(source, flags, data, NULL, &mnt); + mnt = NULL; + err = _sysio_fs_mount(source, fstype, 0, flags, data, NULL, &mnt); if (err) return err; _sysio_root = mnt->mnt_root; + P_REF(_sysio_root); #ifndef DEFER_INIT_CWD /* * It is very annoying to have to set the current working directory. @@ -328,27 +367,19 @@ _sysio_mount(struct pnode *cwd, const void *data) { int err; - struct fsswent *fssw; struct intent intent; - struct pnode *tgt; + struct pnode *tocover; struct mount *mnt; /* - * Find the file system switch entry specified. - */ - fssw = _sysio_fssw_lookup(filesystemtype); - if (!fssw) - return -ENODEV; - - /* * Look up the target path node. */ INTENT_INIT(&intent, INT_GETATTR, NULL, NULL); - err = _sysio_namei(cwd, target, 0, &intent, &tgt); + err = _sysio_namei(cwd, target, 0, &intent, &tocover); if (err) return err; - if (tgt == _sysio_root) { + if (tocover == _sysio_root) { /* * Attempting to mount over root. */ @@ -358,14 +389,16 @@ _sysio_mount(struct pnode *cwd, * Do the deed. */ err = - (*fssw->fssw_ops.fsswop_mount)(source, + _sysio_fs_mount(source, + filesystemtype, + 0, mountflags, data, - tgt, + tocover, &mnt); } if (err) - P_RELE(tgt); + P_PUT(tocover); return err; } @@ -412,7 +445,7 @@ SYSIO_INTERFACE_NAME(umount)(const char mnt = pno->p_mount; if (!err && mnt->mnt_root != pno) err = -EINVAL; - P_RELE(pno); /* was ref'd */ + P_PUT(pno); /* was ref'd */ if (err) goto out; @@ -444,6 +477,10 @@ _sysio_unmount_all() err = 0; while ((mnt = mounts.lh_first)) { pno = mnt->mnt_root; + if (pno == _sysio_root) { + P_RELE(_sysio_root); + _sysio_root = NULL; + } /* * If this is an automount generated mount, the root * has no reference. We can accomplish the dismount with a @@ -454,8 +491,6 @@ _sysio_unmount_all() err = _sysio_do_unmount(mnt); if (err) break; - if (pno == _sysio_root) - _sysio_root = NULL; } return err; @@ -668,7 +703,6 @@ _sysio_automount(struct pnode *mntpno) ssize_t cc; char *fstype, *source, *opts; unsigned flags; - struct fsswent *fssw; struct mount *mnt; /* @@ -711,25 +745,17 @@ _sysio_automount(struct pnode *mntpno) err = parse_automount_spec(buf, &fstype, &source, &opts); if (err) goto out; - flags = 0; if (opts) opts = parse_opts(opts, &flags); /* - * Find the file system switch entry specified. - */ - fssw = _sysio_fssw_lookup(fstype); - if (!fssw) { - err = -ENODEV; - goto out; - } - - /* * Do the deed. */ assert(mntpno->p_parent->p_ref); err = - (*fssw->fssw_ops.fsswop_mount)(source, + _sysio_fs_mount(source, + fstype, + MOUNT_ST_IFAUTO, flags, opts, mntpno->p_parent, Index: namei.c =================================================================== RCS file: /cvsroot/libsysio/libsysio/src/namei.c,v retrieving revision 1.29 retrieving revision 1.30 diff -u -w -b -B -p -r1.29 -r1.30 --- namei.c 22 Apr 2008 21:56:03 -0000 1.29 +++ namei.c 17 Jun 2008 17:18:57 -0000 1.30 @@ -90,14 +90,9 @@ lookup(struct pnode *parent, int err; struct pnode *pno; - assert(parent != NULL); - /* - * The parent must be valid and a directory. - */ - if (!parent->p_parent) - return -ENOENT; - if (!S_ISDIR(parent->p_base->pb_ino->i_stbuf.st_mode)) - return -ENOTDIR; + assert(parent != NULL && + parent->p_parent && + S_ISDIR(parent->p_base->pb_ino->i_stbuf.st_mode)); /* * Sometimes we don't want to check permissions. At initialization @@ -113,20 +108,60 @@ lookup(struct pnode *parent, * Short-circuit `.' and `..'; We don't cache those. */ pno = NULL; - if (name->len == 1 && name->name[0] == '.') + if (name->len == 1 && name->name[0] == '.') { pno = parent; - else if (name->len == 2 && + P_GET(pno); + } else if (name->len == 2 && name->name[0] == '.' && name->name[1] == '.') { - while (parent->p_mount->mnt_root == parent && - parent != parent->p_mount->mnt_covers) - parent = parent->p_mount->mnt_covers; - pno = parent->p_parent; - assert(pno); - } - if (pno) - P_REF(pno); - else { + int parent_is_locked; + struct pnode *child; + + parent_is_locked = 1; + /* + * Careful not to enter deadly embrace. Only + * one node in any given type locked while we're doing this. + */ + pno = parent; + if (pno == pno->p_parent && pno->p_cover != pno) { + + /* + * This node loops on itself and is not the root + * of some name-space. It's an interior mount-point. + */ + P_REF(pno); /* ref passed parent */ + do { + struct mount *mnt; + + /* + * Only the mount record has the pointer + * to the covered path node. + */ + mnt = pno->p_mount; + MNT_GET(mnt); + assert(pno == mnt->mnt_root && + pno != mnt->mnt_covers); + P_PUT(pno); + parent_is_locked = 0; + pno = mnt->mnt_covers; + P_GET(pno); + MNT_PUT(mnt); + } while (pno == pno->p_parent && pno->p_cover != pno); + } + /* + * Now, move to parent of this node. + */ + child = pno; + if (parent_is_locked) + P_REF(child); + pno = pno->p_parent; + P_PUT(child); + P_GET(pno); + if (!parent_is_locked) + child = parent; + P_GET(child); + P_RELE(child); + } else { /* * Get cache entry then. */ @@ -140,8 +175,8 @@ lookup(struct pnode *parent, struct pnode *cover; cover = pno->p_cover; - P_REF(cover); - P_RELE(pno); + P_GET(cover); + P_PUT(pno); pno = cover; } } @@ -215,22 +250,25 @@ _sysio_path_walk(struct pnode *parent, s (void )_sysio_namei(nd->nd_root, icwd, 0, NULL, &parent); if (_sysio_p_chdir(parent) != 0) abort(); + P_PUT(parent); } #endif /* * (Re)Validate the parent. */ + P_GET(parent); err = _sysio_p_validate(parent, NULL, NULL); - if (err) + if (err) { + P_PUT(parent); return err; + } /* * Prime everything for the loop. Will need another reference to the * initial directory. It'll be dropped later. */ nd->nd_pno = parent; - P_REF(nd->nd_pno); _sysio_next_component(nd->nd_path, &next); path = next.name; parent = NULL; @@ -270,6 +308,8 @@ _sysio_path_walk(struct pnode *parent, s /* * Handle symbolic links with recursion. Yuck! */ + P_REF(nd->nd_pno); + P_PUT(nd->nd_pno); ND_INIT(&nameidata, (nd->nd_flags | ND_NEGOK), lpath, @@ -278,28 +318,36 @@ _sysio_path_walk(struct pnode *parent, s nameidata.nd_slicnt = nd->nd_slicnt + 1; err = _sysio_path_walk(nd->nd_pno->p_parent, &nameidata); + P_GET(nd->nd_pno); + P_RELE(nd->nd_pno); free(lpath); if (err) break; - P_RELE(nd->nd_pno); + P_PUT(nd->nd_pno); nd->nd_pno = nameidata.nd_pno; ino = nd->nd_pno->p_base->pb_ino; } #ifdef AUTOMOUNT_FILE_NAME else if (ino && - S_ISDIR(ino->i_stbuf.st_mode) && - (nd->nd_pno->p_mount->mnt_flags & MOUNT_F_AUTO) && nd->nd_amcnt < MAX_MOUNT_DEPTH && - ino->i_stbuf.st_mode & S_ISUID) { + S_ISDIR(ino->i_stbuf.st_mode) && + ino->i_stbuf.st_mode & S_ISUID && + (nd->nd_pno->p_mount->mnt_flags & MOUNT_F_AUTO)) { + struct mount *mnt; struct pnode *pno; /* - * We're committed to a lookup. It's time to see if - * we're going to do it in an automount-point and - * arrange the mount if so. + * Handle directories that hint they might + * be automount-points. */ - assert(!nd->nd_pno->p_cover); + mnt = nd->nd_pno->p_mount; + MNT_GET(mnt); + err = + nd->nd_pno->p_mount->mnt_flags & MOUNT_F_AUTO + ? 0 + : -EACCES; pno = NULL; + if (!err) { err = lookup(nd->nd_pno, &_sysio_mount_file_name, @@ -307,6 +355,8 @@ _sysio_path_walk(struct pnode *parent, s NULL, NULL, 1); + assert(!err || (err && !pno)); + } if (!err && (err = _sysio_automount(pno)) == 0) { /* * All went well. Need to switch @@ -322,7 +372,7 @@ _sysio_path_walk(struct pnode *parent, s * infinite loop. */ nd->nd_pno = nd->nd_pno->p_cover; - P_REF(nd->nd_pno); + P_GET(nd->nd_pno); ino = nd->nd_pno->p_base->pb_ino; assert(ino); @@ -334,7 +384,8 @@ _sysio_path_walk(struct pnode *parent, s } if (pno) - P_RELE(pno); + P_PUT(pno); + MNT_PUT(mnt); if (!err) { /* * Must go back top and retry with this @@ -424,8 +475,13 @@ _sysio_path_walk(struct pnode *parent, s break; } path = NULL; /* Stop that! */ - if ((parent->p_mount->mnt_fs != - nd->nd_pno->p_mount->mnt_fs)) { + /* + * Next check requires no further locks. We are preventing + * the destruction of the mount records by holding locks + * on the two path nodes and the FS field is immutable. + */ + if (!(parent->p_mount == nd->nd_pno->p_mount || + parent->p_mount->mnt_fs == nd->nd_pno->p_mount->mnt_fs)) { /* * Crossed into a new fs. We'll want the next lookup * to include the path again. @@ -434,9 +490,9 @@ _sysio_path_walk(struct pnode *parent, s } /* - * Release the parent. + * Finished with the current parent. */ - P_RELE(parent); + P_PUT(parent); parent = NULL; } @@ -457,18 +513,18 @@ _sysio_path_walk(struct pnode *parent, s } /* - * Drop reference to parent if set. Either we have a dup of the original + * Put the parent if present. Either we have a dup of the original * parent or an intermediate reference. */ if (parent) - P_RELE(parent); + P_PUT(parent); /* - * On error, we will want to drop our reference to the current + * On error, we will want to drop the current * path node if at end. */ if (err && nd->nd_pno) { - P_RELE(nd->nd_pno); + P_PUT(nd->nd_pno); nd->nd_pno = NULL; } Index: open.c =================================================================== RCS file: /cvsroot/libsysio/libsysio/src/open.c,v retrieving revision 1.31 retrieving revision 1.32 diff -u -w -b -B -p -r1.31 -r1.32 --- open.c 19 Sep 2007 16:01:33 -0000 1.31 +++ open.c 17 Jun 2008 17:18:57 -0000 1.32 @@ -95,8 +95,8 @@ _sysio_open(struct pnode *pno, int flags if (ro) return -EROFS; err = _sysio_p_validate(pno->p_parent, NULL, NULL); - if (!err) - err = PNOP_OPEN(pno, flags, mode); + if (!err && (err = PNOP_OPEN(pno, flags, mode)) == 0) + I_REF(pno->p_base->pb_ino); } else if ((flags & (O_CREAT|O_EXCL)) == (O_CREAT|O_EXCL)) err = -EEXIST; else if (!pno->p_base->pb_ino) @@ -190,15 +190,15 @@ SYSIO_INTERFACE_NAME(open)(const char *p if (rtn < 0) goto error; - P_RELE(pno); + FIL_PUT(fil); SYSIO_INTERFACE_RETURN(rtn, 0, open, "%d", 0); error: if (fil) - F_RELE(fil); + FIL_PUT(fil); if (pno) - P_RELE(pno); + P_PUT(pno); SYSIO_INTERFACE_RETURN(-1, rtn, open, "%d", 0); } Index: readlink.c =================================================================== RCS file: /cvsroot/libsysio/libsysio/src/readlink.c,v retrieving revision 1.10 retrieving revision 1.11 diff -u -w -b -B -p -r1.10 -r1.11 --- readlink.c 2 Jul 2007 18:58:17 -0000 1.10 +++ readlink.c 17 Jun 2008 17:18:57 -0000 1.11 @@ -75,7 +75,7 @@ SYSIO_INTERFACE_NAME(readlink)(const cha } err = PNOP_READLINK(pno, buf, bufsiz); error: - P_RELE(pno); + P_PUT(pno); out: #ifdef HAVE_POSIX_1003_READLINK #define _rtnfmt "%zd" Index: rename.c =================================================================== RCS file: /cvsroot/libsysio/libsysio/src/rename.c,v retrieving revision 1.14 retrieving revision 1.15 diff -u -w -b -B -p -r1.14 -r1.15 --- rename.c 2 Jul 2007 18:58:17 -0000 1.14 +++ rename.c 17 Jun 2008 17:18:57 -0000 1.15 @@ -86,6 +86,8 @@ SYSIO_INTERFACE_NAME(rename)(const char old = NULL; break; } + P_REF(old); + P_PUT(old); /* * Resolve newpath to a path node. */ @@ -100,8 +102,13 @@ SYSIO_INTERFACE_NAME(rename)(const char new = NULL; break; } + P_REF(new); + P_PUT(new); + _sysio_p_get2(old, new); err = _sysio_p_rename(old, new); + P_PUT(old); + P_PUT(new); } while (0); if (new) Index: rmdir.c =================================================================== RCS file: /cvsroot/libsysio/libsysio/src/rmdir.c,v retrieving revision 1.22 retrieving revision 1.23 diff -u -w -b -B -p -r1.22 -r1.23 --- rmdir.c 2 Jul 2007 18:58:17 -0000 1.22 +++ rmdir.c 17 Jun 2008 17:18:57 -0000 1.23 @@ -78,7 +78,7 @@ SYSIO_INTERFACE_NAME(rmdir)(const char * break; } while (0); if (pno) - P_RELE(pno); + P_PUT(pno); SYSIO_INTERFACE_RETURN(err ? -1 : 0, err, rmdir, "%d", 0); } Index: rw.c =================================================================== RCS file: /cvsroot/libsysio/libsysio/src/rw.c,v retrieving revision 1.28 retrieving revision 1.29 diff -u -w -b -B -p -r1.28 -r1.29 --- rw.c 30 Nov 2007 18:10:33 -0000 1.28 +++ rw.c 17 Jun 2008 17:18:57 -0000 1.29 @@ -222,7 +222,7 @@ _sysio_iiox(int writing, /* * Opened for proper access? */ - if (!F_CHKRW(fil, writing ? 'w' : 'r')) { + if (!FIL_CHKRW(fil, writing ? 'w' : 'r')) { err = -EBADF; break; } @@ -311,11 +311,16 @@ _do_ireadx(int fd, fd, iov_count, iov, xtv_count, xtv); + do { fil = _sysio_fd_find(fd); - if (fil == NULL) - SYSIO_INTERFACE_RETURN(IOID_FAIL, -EBADF, ireadx, "%p", 0); - if (fil->f_pno->p_base->pb_ino == NULL) - SYSIO_INTERFACE_RETURN(IOID_FAIL, -ESTALE, ireadx, "%p", 0); + if (fil == NULL) { + err = -EBADF; + break; + } + if (fil->f_pno->p_base->pb_ino == NULL) { + err = -ESTALE; + break; + } err = _sysio_iiox(READ, fil, @@ -323,6 +328,9 @@ _do_ireadx(int fd, xtv, xtv_count, release_xtvec, completio, &ioctx); + } while (0); + if (fil) + FIL_PUT(fil); SYSIO_INTERFACE_RETURN(err ? IOID_FAIL : ioctx, err, ireadx, "%p", 0); } @@ -361,11 +369,16 @@ _do_iwritex(int fd, fd, iov_count, iov, xtv_count, xtv); + do { fil = _sysio_fd_find(fd); - if (fil == NULL) - SYSIO_INTERFACE_RETURN(IOID_FAIL, -EBADF, iwritex, "%p", 0); - if (fil->f_pno->p_base->pb_ino == NULL) - SYSIO_INTERFACE_RETURN(IOID_FAIL, -ESTALE, iwritex, "%p", 0); + if (fil == NULL) { + err = -EBADF; + break; + } + if (fil->f_pno->p_base->pb_ino == NULL) { + err = -ESTALE; + break; + } err = _sysio_iiox(WRITE, fil, @@ -373,6 +386,9 @@ _do_iwritex(int fd, xtv, xtv_count, release_xtvec, completio, &ioctx); + } while (0); + if (fil) + FIL_PUT(fil); SYSIO_INTERFACE_RETURN(err ? IOID_FAIL : ioctx, err, iwritex, "%p", 0); } @@ -913,6 +929,8 @@ _do_iiov(direction dir, void *))_sysio_fcompletio, &ioctx); } while (0); + if (fil) + FIL_PUT(fil); if (err && xtv) free(xtv); if (dir == READ) Index: stat.c =================================================================== RCS file: /cvsroot/libsysio/libsysio/src/stat.c,v retrieving revision 1.21 retrieving revision 1.22 diff -u -w -b -B -p -r1.21 -r1.22 --- stat.c 19 Sep 2007 16:01:33 -0000 1.21 +++ stat.c 17 Jun 2008 17:18:57 -0000 1.22 @@ -83,6 +83,7 @@ _sysio_fxstat(int ver, int fildes, struc * want fresh ones. */ err = PNOP_GETATTR(fil->f_pno, stat_buf); + FIL_PUT(fil); out: SYSIO_INTERFACE_RETURN(err ? -1 : 0, err, fxstat, "%d%sY", stat_buf); } @@ -116,7 +117,7 @@ _sysio_xstatnd(int ver, (void )memcpy(stat_buf, &pno->p_base->pb_ino->i_stbuf, sizeof(struct intnl_stat)); - P_RELE(pno); + P_PUT(pno); out: SYSIO_INTERFACE_RETURN(err ? -1 : 0, err, xstatnd, "%d%sY", stat_buf); } Index: statvfs.c =================================================================== RCS file: /cvsroot/libsysio/libsysio/src/statvfs.c,v retrieving revision 1.19 retrieving revision 1.20 diff -u -w -b -B -p -r1.19 -r1.20 --- statvfs.c 26 Oct 2007 19:48:23 -0000 1.19 +++ statvfs.c 17 Jun 2008 17:18:57 -0000 1.20 @@ -68,7 +68,7 @@ _sysio_statvfs(const char *path, struct return err; err = PNOP_STATVFS(pno, buf); - P_RELE(pno); + P_PUT(pno); return err; } @@ -84,6 +84,7 @@ _sysio_fstatvfs(int fd, struct intnl_sta return -EBADF; err = PNOP_STATVFS(filp->f_pno, buf); + FIL_PUT(filp); return err; } Index: symlink.c =================================================================== RCS file: /cvsroot/libsysio/libsysio/src/symlink.c,v retrieving revision 1.19 retrieving revision 1.20 diff -u -w -b -B -p -r1.19 -r1.20 --- symlink.c 20 Nov 2007 18:01:42 -0000 1.19 +++ symlink.c 17 Jun 2008 17:18:57 -0000 1.20 @@ -79,7 +79,7 @@ SYSIO_INTERFACE_NAME(symlink)(const char err = _sysio_p_symlink(oldpath, pno); } while (0); if (pno) - P_RELE(pno); + P_PUT(pno); SYSIO_INTERFACE_RETURN(err ? -1 : 0, err, symlink, "%d", 0); } Index: truncate.c =================================================================== RCS file: /cvsroot/libsysio/libsysio/src/truncate.c,v retrieving revision 1.18 retrieving revision 1.19 diff -u -w -b -B -p -r1.18 -r1.19 --- truncate.c 2 Jul 2007 18:58:17 -0000 1.18 +++ truncate.c 17 Jun 2008 17:18:57 -0000 1.19 @@ -96,7 +96,7 @@ PREPEND(_, SYSIO_INTERFACE_NAME(truncate if (err) goto out; err = do_truncate(pno, length); - P_RELE(pno); + P_PUT(pno); out: SYSIO_INTERFACE_RETURN(err ? -1 : 0, err, truncate, "%d", 0); @@ -130,12 +130,14 @@ PREPEND(_, SYSIO_INTERFACE_NAME(ftruncat SYSIO_INTERFACE_ENTER(ftruncate, "%d%oZ", fd, length); err = 0; fil = _sysio_fd_find(fd); - if (!(fil && F_CHKRW(fil, 'w'))) { + if (!(fil && FIL_CHKRW(fil, 'w'))) { err = -EBADF; goto out; } err = do_truncate(fil->f_pno, length); out: + if (fil) + FIL_PUT(fil); SYSIO_INTERFACE_RETURN(err ? -1 : 0, err, ftruncate, "%d", 0); } Index: unlink.c =================================================================== RCS file: /cvsroot/libsysio/libsysio/src/unlink.c,v retrieving revision 1.20 retrieving revision 1.21 diff -u -w -b -B -p -r1.20 -r1.21 --- unlink.c 2 Jul 2007 18:58:17 -0000 1.20 +++ unlink.c 17 Jun 2008 17:18:57 -0000 1.21 @@ -79,7 +79,7 @@ SYSIO_INTERFACE_NAME(unlink)(const char break; } while (0); if (pno) - P_RELE(pno); + P_PUT(pno); SYSIO_INTERFACE_RETURN(err ? -1 : 0, err, unlink, "%d", 0); } Index: utime.c =================================================================== RCS file: /cvsroot/libsysio/libsysio/src/utime.c,v retrieving revision 1.9 retrieving revision 1.10 diff -u -w -b -B -p -r1.9 -r1.10 --- utime.c 2 Jul 2007 18:58:18 -0000 1.9 +++ utime.c 17 Jun 2008 17:18:57 -0000 1.10 @@ -89,7 +89,7 @@ SYSIO_INTERFACE_NAME(utime)(const char * stbuf.st_mtime = buf->modtime; err = _sysio_p_setattr(pno, SETATTR_ATIME | SETATTR_MTIME, &stbuf); - P_RELE(pno); + P_PUT(pno); out: /* * Note: Pass the utimbuf buffer to the tracing routines some day. |