Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement locking with OFD locks when present. #91

Draft
wants to merge 1 commit into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions configure.ac
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,8 @@ AC_CHECK_HEADERS( \
AC_C_BIGENDIAN
AC_C_CONST

AC_CHECK_DECLS([F_OFD_SETLK], [], [], [[#include <fcntl.h>]])

##
# Checks for library functions
##
Expand Down
20 changes: 19 additions & 1 deletion diod/ioctx.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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)
{
Expand All @@ -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;

Expand Down Expand Up @@ -407,6 +423,8 @@ ioctx_testlock (IOCtx ioctx, int type)
return ret;
}

#endif

u32
ioctx_iounit (IOCtx ioctx)
{
Expand Down
7 changes: 5 additions & 2 deletions diod/ioctx.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
135 changes: 134 additions & 1 deletion diod/ops.c
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -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);
Expand All @@ -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)
{
Expand Down