diff --git a/configure.ac b/configure.ac index 419056e7..35d41947 100644 --- a/configure.ac +++ b/configure.ac @@ -75,6 +75,8 @@ AC_CHECK_HEADERS( \ AC_C_BIGENDIAN AC_C_CONST +AC_CHECK_DECLS([F_OFD_SETLK], [], [], [[#include ]]) + ## # Checks for library functions ## diff --git a/diod/ioctx.c b/diod/ioctx.c index c1265e4d..060e5e44 100644 --- a/diod/ioctx.c +++ b/diod/ioctx.c @@ -53,7 +53,9 @@ struct ioctx_struct { int refcount; int fd; DIR *dir; + #if !HAVE_DECL_F_OFD_SETLK int lock_type; + #endif Npqid qid; u32 iounit; u32 open_flags; @@ -165,7 +167,9 @@ _ioctx_create_open (Npuser *user, Path path, int flags, u32 mode) } pthread_mutex_init (&ioctx->lock, NULL); ioctx->refcount = 1; + #if !HAVE_DECL_F_OFD_SETLK ioctx->lock_type = LOCK_UN; + #endif ioctx->dir = NULL; ioctx->open_flags = flags; ioctx->user = user; @@ -353,6 +357,18 @@ ioctx_fsync(IOCtx ioctx) return fsync (ioctx->fd); } +#if HAVE_DECL_F_OFD_SETLK + +int +ioctx_fcntl_lock(IOCtx ioctx, int cmd, struct flock *l) +{ + if (fcntl(ioctx->fd, cmd, l) < 0) + return -1; + return 0; +} + +#else + int ioctx_flock (IOCtx ioctx, int operation) { @@ -370,7 +386,7 @@ ioctx_flock (IOCtx ioctx, int operation) /* If lock of 'type' could be obtained, return LOCK_UN, otherwise LOCK_EX. */ int -ioctx_testlock (IOCtx ioctx, int type) +ioctx_test_flock (IOCtx ioctx, int type) { int ret = LOCK_UN; @@ -407,6 +423,8 @@ ioctx_testlock (IOCtx ioctx, int type) return ret; } +#endif + u32 ioctx_iounit (IOCtx ioctx) { diff --git a/diod/ioctx.h b/diod/ioctx.h index 0b8a24b6..515257ed 100644 --- a/diod/ioctx.h +++ b/diod/ioctx.h @@ -28,9 +28,12 @@ struct dirent *ioctx_readdir(IOCtx ioctx, long *new_offset); void ioctx_rewinddir (IOCtx ioctx); void ioctx_seekdir (IOCtx ioctx, long offset); int ioctx_fsync (IOCtx ioctx); +#if HAVE_DECL_F_OFD_SETLK +int ioctx_fcntl_lock(IOCtx ioctx, int cmd, struct flock *l); +#else int ioctx_flock (IOCtx ioctx, int operation); -int ioctx_testlock (IOCtx ioctx, int operation); - +int ioctx_test_flock (IOCtx ioctx, int operation); +#endif int ioctx_stat (IOCtx ioctx, struct stat *sb); int ioctx_chmod (IOCtx ioctx, u32 mode); int ioctx_chown (IOCtx ioctx, u32 uid, u32 gid); diff --git a/diod/ops.c b/diod/ops.c index 77f960d4..13c62a7d 100644 --- a/diod/ops.c +++ b/diod/ops.c @@ -1253,6 +1253,137 @@ diod_fsync (Npfid *fid) return NULL; } +#if HAVE_DECL_F_OFD_SETLK + +/* Locking note: + * Implement POSIX locks in terms of OFD locks, it will + * at least work for some use cases, but may still deadlock others. + */ + +Npfcall* +diod_lock (Npfid *fid, u8 type, u32 flags, u64 start, u64 length, u32 proc_id, + Npstr *client_id) +{ + Fid *f = fid->aux; + Npfcall *ret; + u8 status = P9_LOCK_ERROR; + struct flock lock; + + if (flags & ~P9_LOCK_FLAGS_BLOCK) { /* only one valid flag for now */ + np_uerror (EINVAL); /* (which we ignore) */ + goto error; + } + if (!f->ioctx) { + msg ("diod_lock: fid is not open"); + np_uerror (EBADF); + goto error; + } + + lock.l_whence = SEEK_SET; + lock.l_start = start; + lock.l_len = length; + lock.l_pid = 0; + + switch (type) { + case P9_LOCK_TYPE_UNLCK: + lock.l_type = F_UNLCK; + if (ioctx_fcntl_lock(f->ioctx, F_OFD_SETLK, &lock) == 0) + status = P9_LOCK_SUCCESS; + break; + case P9_LOCK_TYPE_RDLCK: + lock.l_type = F_RDLCK; + if (ioctx_fcntl_lock(f->ioctx, F_OFD_SETLK, &lock) == 0) + status = P9_LOCK_SUCCESS; + else if (errno == EWOULDBLOCK) + status = P9_LOCK_BLOCKED; + break; + case P9_LOCK_TYPE_WRLCK: + lock.l_type = F_WRLCK; + if (ioctx_fcntl_lock(f->ioctx, F_OFD_SETLK, &lock) == 0) + status = P9_LOCK_SUCCESS; + else if (errno == EWOULDBLOCK) + status = P9_LOCK_BLOCKED; + break; + default: + np_uerror (EINVAL); + goto error; + } + if (!((ret = np_create_rlock (status)))) { + np_uerror (ENOMEM); + goto error; + } + return ret; +error: + errn (np_rerror (), "diod_lock %s@%s:%s", + fid->user->uname, np_conn_get_client_id (fid->conn), + path_s (f->path)); + return NULL; +} + +Npfcall* +diod_getlock (Npfid *fid, u8 type, u64 start, u64 length, u32 proc_id, + Npstr *client_id) +{ + Fid *f = fid->aux; + Npfcall *ret; + char *cid = NULL; + struct flock lock; + + if (!f->ioctx) { + msg ("diod_getlock: fid is not open"); + np_uerror (EBADF); + goto error; + } + if (!(cid = np_strdup (client_id))) { + np_uerror (ENOMEM); + goto error; + } + if (type != P9_LOCK_TYPE_RDLCK && type != P9_LOCK_TYPE_WRLCK) { + np_uerror (EINVAL); + goto error; + } + + lock.l_whence = SEEK_SET; + lock.l_start = start; + lock.l_len = length; + lock.l_pid = 0; + + switch (type) { + case P9_LOCK_TYPE_UNLCK: + lock.l_type = F_UNLCK; + case P9_LOCK_TYPE_RDLCK: + lock.l_type = F_RDLCK; + case P9_LOCK_TYPE_WRLCK: + lock.l_type = F_WRLCK; + default: + np_uerror (EINVAL); + goto error; + } + + if (ioctx_fcntl_lock(f->ioctx, F_OFD_GETLK, &lock) != 0) { + np_uerror (errno); + goto error; + } + + type = (lock.l_type == F_UNLCK) ? P9_LOCK_TYPE_UNLCK : type; + if (!((ret = np_create_rgetlock(type, start, length, lock.l_pid, cid)))) { + np_uerror (ENOMEM); + goto error; + } + free (cid); + return ret; +error: + errn (np_rerror (), "diod_getlock %s@%s:%s", + fid->user->uname, np_conn_get_client_id (fid->conn), + path_s (f->path)); + if (cid) + free (cid); + return NULL; +} + +#else + + /* Locking note: * Implement POSIX locks in terms of BSD flock locks. * This at least gets distributed whole-file locking to work. @@ -1331,7 +1462,7 @@ diod_getlock (Npfid *fid, u8 type, u64 start, u64 length, u32 proc_id, goto error; } ftype = (type == P9_LOCK_TYPE_RDLCK) ? LOCK_SH : LOCK_EX; - ftype = ioctx_testlock (f->ioctx, ftype); + ftype = ioctx_test_flock (f->ioctx, ftype); type = (ftype == LOCK_EX) ? P9_LOCK_TYPE_WRLCK : P9_LOCK_TYPE_UNLCK; if (!((ret = np_create_rgetlock(type, start, length, proc_id, cid)))) { np_uerror (ENOMEM); @@ -1348,6 +1479,8 @@ diod_getlock (Npfid *fid, u8 type, u64 start, u64 length, u32 proc_id, return NULL; } +#endif + Npfcall* diod_link (Npfid *dfid, Npfid *fid, Npstr *name) {