/* Locking note: * Implement POSIX locks in terms of BSD flock locks. * This at least gets distributed whole-file locking to work. * Strategies for distributed record locking will deadlock. */ 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 = NULL; u8 status = P9_LOCK_ERROR; if ((f->xflags & XFLAGS_RO)) { np_uerror (EROFS); goto error_quiet; } if (flags & ~P9_LOCK_FLAGS_BLOCK) { /* only one valid flag for now */ np_uerror (EINVAL); /* (which we ignore) */ goto error; } if (_fidstat(f) < 0) goto error_quiet; switch (type) { case F_UNLCK: if (flock (f->fd, LOCK_UN) >= 0) { status = P9_LOCK_SUCCESS; f->lock_type = LOCK_UN; } else status = P9_LOCK_ERROR; break; case F_RDLCK: if (flock (f->fd, LOCK_SH | LOCK_NB) >= 0) { status = P9_LOCK_SUCCESS; f->lock_type = LOCK_SH; } else if (errno == EWOULDBLOCK) { status = P9_LOCK_BLOCKED; } else status = P9_LOCK_ERROR; break; case F_WRLCK: if (flock (f->fd, LOCK_EX | LOCK_NB) >= 0) { status = P9_LOCK_SUCCESS; f->lock_type = LOCK_EX; } 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), f->path); error_quiet: if (ret) free (ret); return NULL; }
/* Locking note: * Implement POSIX locks in terms of BSD flock locks. * This at least gets distributed whole-file locking to work. * Strategies for distributed record locking will deadlock. */ 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; if ((f->flags & DIOD_FID_FLAGS_ROFS)) { np_uerror (EROFS); goto error_quiet; } 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; } switch (type) { case P9_LOCK_TYPE_UNLCK: if (ioctx_flock (f->ioctx, LOCK_UN) == 0) status = P9_LOCK_SUCCESS; break; case P9_LOCK_TYPE_RDLCK: if (ioctx_flock (f->ioctx, LOCK_SH | LOCK_NB) == 0) status = P9_LOCK_SUCCESS; else if (errno == EWOULDBLOCK) status = P9_LOCK_BLOCKED; break; case P9_LOCK_TYPE_WRLCK: if (ioctx_flock (f->ioctx, LOCK_EX | LOCK_NB) == 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)); error_quiet: return NULL; }
static void test_rlock (void) { Npfcall *fc, *fc2; if (!(fc = np_create_rlock (1))) msg_exit ("out of memory"); fc2 = _rcv_buf (fc, P9_RLOCK, __FUNCTION__); assert (fc->u.rlock.status == fc2->u.rlock.status); free (fc); free (fc2); }