lock->l_conn_export = exp;
lock->l_export = NULL;
lock->l_blocking_ast = einfo->ei_cb_bl;
- lock->l_flags |= (*flags & (LDLM_FL_NO_LRU | LDLM_FL_EXCL));
+ lock->l_flags |= (*flags & (LDLM_FL_NO_LRU | LDLM_FL_EXCL |
+ LDLM_FL_ATOMIC_CB));
lock->l_activity = ktime_get_real_seconds();
/* lock not sent to server yet */
RETURN(rc);
}
+
static int
ll_get_grouplock(struct inode *inode, struct file *file, unsigned long arg)
{
RETURN(-EINVAL);
}
- if (ll_file_nolock(file))
- RETURN(-EOPNOTSUPP);
+ if (ll_file_nolock(file))
+ RETURN(-EOPNOTSUPP);
+retry:
+ if (file->f_flags & O_NONBLOCK) {
+ if (!mutex_trylock(&lli->lli_group_mutex))
+ RETURN(-EAGAIN);
+ } else
+ mutex_lock(&lli->lli_group_mutex);
- spin_lock(&lli->lli_lock);
if (fd->fd_flags & LL_FILE_GROUP_LOCKED) {
CWARN("group lock already existed with gid %lu\n",
fd->fd_grouplock.lg_gid);
- spin_unlock(&lli->lli_lock);
- RETURN(-EINVAL);
+ GOTO(out, rc = -EINVAL);
+ }
+ if (arg != lli->lli_group_gid && lli->lli_group_users != 0) {
+ if (file->f_flags & O_NONBLOCK)
+ GOTO(out, rc = -EAGAIN);
+ mutex_unlock(&lli->lli_group_mutex);
+ wait_var_event(&lli->lli_group_users, !lli->lli_group_users);
+ GOTO(retry, rc = 0);
}
LASSERT(fd->fd_grouplock.lg_lock == NULL);
- spin_unlock(&lli->lli_lock);
/**
* XXX: group lock needs to protect all OST objects while PFL
env = cl_env_get(&refcheck);
if (IS_ERR(env))
- RETURN(PTR_ERR(env));
+ GOTO(out, rc = PTR_ERR(env));
rc = cl_object_layout_get(env, obj, &cl);
if (!rc && cl.cl_is_composite)
cl_env_put(env, &refcheck);
if (rc)
- RETURN(rc);
+ GOTO(out, rc);
}
rc = cl_get_grouplock(ll_i2info(inode)->lli_clob,
arg, (file->f_flags & O_NONBLOCK), &grouplock);
- if (rc)
- RETURN(rc);
- spin_lock(&lli->lli_lock);
- if (fd->fd_flags & LL_FILE_GROUP_LOCKED) {
- spin_unlock(&lli->lli_lock);
- CERROR("another thread just won the race\n");
- cl_put_grouplock(&grouplock);
- RETURN(-EINVAL);
- }
+ if (rc)
+ GOTO(out, rc);
fd->fd_flags |= LL_FILE_GROUP_LOCKED;
fd->fd_grouplock = grouplock;
- spin_unlock(&lli->lli_lock);
+ if (lli->lli_group_users == 0)
+ lli->lli_group_gid = grouplock.lg_gid;
+ lli->lli_group_users++;
CDEBUG(D_INFO, "group lock %lu obtained\n", arg);
- RETURN(0);
+out:
+ mutex_unlock(&lli->lli_group_mutex);
+
+ RETURN(rc);
}
static int ll_put_grouplock(struct inode *inode, struct file *file,
struct ll_inode_info *lli = ll_i2info(inode);
struct ll_file_data *fd = LUSTRE_FPRIVATE(file);
struct ll_grouplock grouplock;
+ int rc;
ENTRY;
- spin_lock(&lli->lli_lock);
+ mutex_lock(&lli->lli_group_mutex);
if (!(fd->fd_flags & LL_FILE_GROUP_LOCKED)) {
- spin_unlock(&lli->lli_lock);
- CWARN("no group lock held\n");
- RETURN(-EINVAL);
- }
+ CWARN("no group lock held\n");
+ GOTO(out, rc = -EINVAL);
+ }
LASSERT(fd->fd_grouplock.lg_lock != NULL);
if (fd->fd_grouplock.lg_gid != arg) {
CWARN("group lock %lu doesn't match current id %lu\n",
arg, fd->fd_grouplock.lg_gid);
- spin_unlock(&lli->lli_lock);
- RETURN(-EINVAL);
+ GOTO(out, rc = -EINVAL);
}
grouplock = fd->fd_grouplock;
memset(&fd->fd_grouplock, 0, sizeof(fd->fd_grouplock));
fd->fd_flags &= ~LL_FILE_GROUP_LOCKED;
- spin_unlock(&lli->lli_lock);
cl_put_grouplock(&grouplock);
+
+ lli->lli_group_users--;
+ if (lli->lli_group_users == 0) {
+ lli->lli_group_gid = 0;
+ wake_up_var(&lli->lli_group_users);
+ }
CDEBUG(D_INFO, "group lock %lu released\n", arg);
- RETURN(0);
+ GOTO(out, rc = 0);
+out:
+ mutex_unlock(&lli->lli_group_mutex);
+
+ RETURN(rc);
}
/**
struct mutex lli_pcc_lock;
enum lu_pcc_state_flags lli_pcc_state;
struct pcc_inode *lli_pcc_inode;
+ struct mutex lli_group_mutex;
+ __u64 lli_group_users;
+ unsigned long lli_group_gid;
};
};
mutex_init(&lli->lli_pcc_lock);
lli->lli_pcc_state = PCC_STATE_FL_NONE;
lli->lli_pcc_inode = NULL;
+ mutex_init(&lli->lli_group_mutex);
+ lli->lli_group_users = 0;
+ lli->lli_group_gid = 0;
}
mutex_init(&lli->lli_layout_mutex);
memset(lli->lli_jobid, 0, sizeof(lli->lli_jobid));
oscl->ols_flags = osc_enq2ldlm_flags(enqflags);
oscl->ols_speculative = !!(enqflags & CEF_SPECULATIVE);
+ if (lock->cll_descr.cld_mode == CLM_GROUP)
+ oscl->ols_flags |= LDLM_FL_ATOMIC_CB;
if (oscl->ols_flags & LDLM_FL_HAS_INTENT) {
oscl->ols_flags |= LDLM_FL_BLOCK_GRANTED;
#include <fcntl.h>
#include <sys/ioctl.h>
#include <sys/types.h>
+#include <sys/wait.h>
+#include <sys/uio.h>
#include <sys/stat.h>
#include <time.h>
#include <unistd.h>
close(fd2);
}
+/* Test locking between several fds. */
+static void test40(void)
+{
+ int rc;
+ int fd;
+ int gid;
+ char buf[10000];
+ int i, j, threads = 40;
+
+ /* Create the test file. */
+ fd = open(mainpath, O_RDWR | O_CREAT | O_TRUNC,
+ S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP);
+ ASSERTF(fd >= 0, "creat failed for '%s': %s",
+ mainpath, strerror(errno));
+ /* Lock */
+ gid = 1234;
+ rc = ioctl(fd, LL_IOC_GROUP_LOCK, gid);
+ ASSERTF(rc == 0, "cannot lock '%s' gid %d: %s", mainpath, gid,
+ strerror(errno));
+
+ for (i = 0; i < threads; i++) {
+ rc = fork();
+ ASSERTF(rc >= 0, "fork failed %s", strerror(errno));
+
+ if (rc == 0) {
+ struct iovec io = { .iov_base = buf,
+ .iov_len = sizeof(buf)};
+
+ /* writing to a fixed offset */
+ memset(buf, i, sizeof(buf));
+ rc = pwritev(fd, &io, 1, sizeof(buf) * i);
+ ASSERTF(rc == sizeof(buf), "write failed for '%s' block %d: %s",
+ mainpath, i, strerror(errno));
+
+ close(fd);
+ exit(0);
+ }
+ }
+
+ while ((i = wait(&rc)) > 0);
+
+ /* Check data */
+ for (i = 0; i < threads; i++) {
+ rc = read(fd, buf, sizeof(buf));
+ ASSERTF(rc == sizeof(buf), "read failed for '%s': %s",
+ mainpath, strerror(errno));
+ for (j = 0; j < rc; j++)
+ ASSERTF(i == buf[j], "wrong data at off %d %d != %d",
+ j, i, buf[j]);
+ }
+
+ /* close unlock group lock */
+ rc = close(fd);
+ ASSERTF(rc == 0, "close failed '%s': %s",
+ mainpath, strerror(errno));
+}
+
static void usage(char *prog)
{
fprintf(stderr, "Usage: %s [-d lustre_dir]\n", prog);
PERFORM(test12);
PERFORM(test20);
PERFORM(test30);
+ PERFORM(test40);
return EXIT_SUCCESS;
}
}
run_test 243 "various group lock tests"
-test_244()
+test_244a()
{
test_mkdir $DIR/$tdir
dd if=/dev/zero of=$DIR/$tdir/$tfile bs=1M count=35
error "sendfile+grouplock failed"
rm -rf $DIR/$tdir
}
-run_test 244 "sendfile with group lock tests"
+run_test 244a "sendfile with group lock tests"
+
+test_244b()
+{
+ [ $PARALLEL == "yes" ] && skip "skip parallel run" && return
+
+ local threads=50
+ local size=$((1024*1024))
+
+ test_mkdir $DIR/$tdir
+ for i in $(seq 1 $threads); do
+ local file=$DIR/$tdir/file_$((i / 10))
+ $MULTIOP $file OG1234w$size_$((i % 3))w$size_$((i % 4))g1234c &
+ local pids[$i]=$!
+ done
+ for i in $(seq 1 $threads); do
+ wait ${pids[$i]}
+ done
+}
+run_test 244b "multi-threaded write with group lock"
test_245() {
local flagname="multi_mod_rpcs"