#define del_wait_queue(p) do { list_del(&(p)->sleeping); } while (0)
#define remove_wait_queue(q,p) do { list_del(&(p)->sleeping); } while (0)
+#define DECLARE_WAIT_QUEUE_HEAD(HEAD) \
+ wait_queue_head_t HEAD = { \
+ .sleepers = LIST_HEAD_INIT(HEAD.sleepers) \
+ }
#define init_waitqueue_head(l) INIT_LIST_HEAD(&(l)->sleepers)
#define wake_up(l) do { int a; a++; } while (0)
#define TASK_INTERRUPTIBLE 0
#define LDLM_FL_WARN 0x008000 /* see ldlm_cli_cancel_unused */
#define LDLM_FL_DISCARD_DATA 0x010000 /* discard (no writeback) on cancel */
+#define LDLM_FL_NO_TIMEOUT 0x020000 /* Blocked by group lock - wait
+ * indefinitely */
+
/* file & record locking */
#define LDLM_FL_BLOCK_NOWAIT 0x040000 // server told not to wait if blocked
#define LDLM_FL_TEST_LOCK 0x080000 // return blocking lock
if (lock->l_resource->lr_type == LDLM_FLOCK) { \
CDEBUG(level, "### " format \
" ns: %s lock: %p/"LPX64" lrc: %d/%d,%d mode: %s/%s " \
- "res: "LPU64"/"LPU64" rrc: %d type: %s pid: %d " \
+ "res: "LPU64"/"LPU64" rrc: %d type: %s pid: "LPU64" " \
"["LPU64"->"LPU64"] flags: %x remote: "LPX64 \
" expref: %d\n" , ## a, \
lock->l_resource->lr_namespace->ns_name, lock, \
struct ldlm_extent {
__u64 start;
__u64 end;
+ __u64 gid;
};
struct ldlm_flock {
__u64 start;
__u64 end;
+ __u64 pid;
+ __u64 blocking_pid;
__u64 blocking_export;
- pid_t blocking_pid;
- pid_t pid;
};
/* it's important that the fields of the ldlm_extent structure match
#define LL_IOC_LOV_GETSTRIPE _IOW ('f', 155, long)
#define LL_IOC_LOV_SETEA _IOW ('f', 156, long)
#define LL_IOC_RECREATE_OBJ _IOW ('f', 157, long)
+#define LL_IOC_CW_LOCK _IOW ('f', 158, long)
+#define LL_IOC_CW_UNLOCK _IOW ('f', 159, long)
#define O_LOV_DELAY_CREATE 0100000000 /* hopefully this does not conflict */
#define LL_FILE_IGNORE_LOCK 0x00000001
+#define LL_FILE_CW_LOCKED 0x00000002
#define LOV_USER_MAGIC_V1 0x0BD10BD0
#define LOV_USER_MAGIC LOV_USER_MAGIC_V1
} \
} while(0)
+#ifdef __KERNEL__
/* The idea here is to synchronise two threads to force a race. The
* first thread that calls this with a matching fail_loc is put to
* sleep. The next thread that calls with the same fail_loc wakes up
wake_up(&obd_race_waitq); \
} \
} while(0)
+#else
+/* sigh. an expedient fix until OBD_RACE is fixed up */
+#define OBD_RACE(foo) LBUG()
+#endif
#define fixme() CDEBUG(D_OTHER, "FIXME\n");
-$Id: bproc-patch-2.4.20,v 1.6 2004/03/19 01:09:33 zab Exp $
+$Id: bproc-patch-2.4.20,v 1.7 2004/03/19 06:33:08 phil Exp $
Index: linux/fs/exec.c
===================================================================
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
-+ * $Id: bproc-patch-2.4.20,v 1.6 2004/03/19 01:09:33 zab Exp $
++ * $Id: bproc-patch-2.4.20,v 1.7 2004/03/19 06:33:08 phil Exp $
+ *-----------------------------------------------------------------------*/
+#include <linux/kernel.h>
+#include <linux/sched.h>
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
-+ * $Id: bproc-patch-2.4.20,v 1.6 2004/03/19 01:09:33 zab Exp $
++ * $Id: bproc-patch-2.4.20,v 1.7 2004/03/19 06:33:08 phil Exp $
+ *-----------------------------------------------------------------------*/
+#ifndef _LINUX_BPROC_H
+#define _LINUX_BPROC_H
/* Determine if the lock is compatible with all locks on the queue.
* We stop walking the queue if we hit ourselves so we don't take
- * conflicting locks enqueued after us into accound, or we'd wait forever. */
+ * conflicting locks enqueued after us into accound, or we'd wait forever.
+ *
+ * 0 if the lock is not compatible
+ * 1 if the lock is compatible
+ * 2 if this group lock is compatible and requires no further checking
+ * negative error, such as EWOULDBLOCK for group locks
+ */
static int
ldlm_extent_compat_queue(struct list_head *queue, struct ldlm_lock *req,
- int send_cbs)
+ int send_cbs, int *flags, ldlm_error_t *err)
{
struct list_head *tmp;
struct ldlm_lock *lock;
RETURN(compat);
/* locks are compatible, overlap doesn't matter */
- if (lockmode_compat(lock->l_req_mode, req_mode))
- continue;
+ if (lockmode_compat(lock->l_req_mode, req_mode)) {
+ /* nonCW locks are compatible, overlap doesn't matter */
+ if (req_mode != LCK_CW)
+ continue;
+
+ /* If we are trying to get a CW lock and there is
+ another one of this kind, we need to compare gid */
+ if (req->l_policy_data.l_extent.gid ==
+ lock->l_policy_data.l_extent.gid) {
+ if (lock->l_req_mode == lock->l_granted_mode)
+ RETURN(2);
+
+ /* If we are in nonblocking mode - return
+ immediately */
+ if (*flags & LDLM_FL_BLOCK_NOWAIT) {
+ compat = -EWOULDBLOCK;
+ goto destroylock;
+ }
+ /* If this group lock is compatible with another
+ * group lock on the waiting list, they must be
+ * together in the list, so they can be granted
+ * at the same time. Otherwise the later lock
+ * can get stuck behind another, incompatible,
+ * lock. */
+ ldlm_resource_insert_lock_after(lock, req);
+ /* Because 'lock' is not granted, we can stop
+ * processing this queue and return immediately.
+ * There is no need to check the rest of the
+ * list. */
+ RETURN(0);
+ }
+ }
- /* if lock doesn't overlap skip it */
- if (lock->l_policy_data.l_extent.end < req_start ||
- lock->l_policy_data.l_extent.start > req_end)
+ if (lock->l_req_mode == LCK_CW) {
+ /* If compared lock is CW, then requested is PR/PW/ =>
+ * this is not compatible; extent range does not
+ * matter */
+ if (*flags & LDLM_FL_BLOCK_NOWAIT) {
+ compat = -EWOULDBLOCK;
+ goto destroylock;
+ } else {
+ *flags |= LDLM_FL_NO_TIMEOUT;
+ }
+ } else if (lock->l_policy_data.l_extent.end < req_start ||
+ lock->l_policy_data.l_extent.start > req_end) {
+ /* if a non-CW lock doesn't overlap skip it */
continue;
+ }
if (!send_cbs)
RETURN(0);
ldlm_add_ast_work_item(lock, req, NULL, 0);
}
+ return(compat);
+destroylock:
+ list_del_init(&req->l_res_link);
+ ldlm_lock_destroy(req);
+ *err = compat;
RETURN(compat);
}
{
struct ldlm_resource *res = lock->l_resource;
struct list_head rpc_list = LIST_HEAD_INIT(rpc_list);
- int rc;
+ int rc, rc2;
ENTRY;
LASSERT(list_empty(&res->lr_converting));
+ *err = ELDLM_OK;
if (!first_enq) {
+ /* Careful observers will note that we don't handle -EWOULDBLOCK
+ * here, but it's ok for a non-obvious reason -- compat_queue
+ * can only return -EWOULDBLOCK if (flags & BLOCK_NOWAIT).
+ * flags should always be zero here, and if that ever stops
+ * being true, we want to find out. */
+ LASSERT(*flags == 0);
LASSERT(res->lr_tmp != NULL);
- rc = ldlm_extent_compat_queue(&res->lr_granted, lock, 0);
- if (!rc)
- RETURN(LDLM_ITER_STOP);
- rc = ldlm_extent_compat_queue(&res->lr_waiting, lock, 0);
- if (!rc)
+ rc = ldlm_extent_compat_queue(&res->lr_granted, lock, 0, flags,
+ err);
+ if (rc == 1) {
+ rc = ldlm_extent_compat_queue(&res->lr_waiting, lock, 0,
+ flags, err);
+ }
+ if (rc == 0)
RETURN(LDLM_ITER_STOP);
ldlm_resource_unlink_lock(lock);
restart:
LASSERT(res->lr_tmp == NULL);
res->lr_tmp = &rpc_list;
- rc = ldlm_extent_compat_queue(&res->lr_granted, lock, 1);
- rc += ldlm_extent_compat_queue(&res->lr_waiting, lock, 1);
+ rc = ldlm_extent_compat_queue(&res->lr_granted, lock, 1, flags, err);
+ if (rc < 0)
+ RETURN(rc); /* lock was destroyed */
+ if (rc == 2)
+ goto grant;
+
+ rc2 = ldlm_extent_compat_queue(&res->lr_waiting, lock, 1, flags, err);
+ if (rc2 < 0)
+ RETURN(rc2); /* lock was destroyed */
res->lr_tmp = NULL;
- if (rc != 2) {
- /* If either of the compat_queue()s returned 0, then we
+ if (rc + rc2 == 2) {
+ grant:
+ ldlm_extent_policy(res, lock, flags);
+ ldlm_resource_unlink_lock(lock);
+ ldlm_grant_lock(lock, NULL, 0, 0);
+ } else {
+ /* If either of the compat_queue()s returned failure, then we
* have ASTs to send and must go onto the waiting list.
*
* bug 2322: we used to unlink and re-add here, which was a
if (rc == -ERESTART)
GOTO(restart, -ERESTART);
*flags |= LDLM_FL_BLOCK_GRANTED;
- } else {
- ldlm_extent_policy(res, lock, flags);
- ldlm_resource_unlink_lock(lock);
- ldlm_grant_lock(lock, NULL, 0, 0);
}
RETURN(0);
}
int overlaps = 0;
ENTRY;
- CDEBUG(D_DLMTRACE, "flags %#x pid %u mode %u start "LPU64" end "LPU64
- "\n", *flags, new->l_policy_data.l_flock.pid, mode,
+ CDEBUG(D_DLMTRACE, "flags %#x pid "LPU64" mode %u start "LPU64" end "
+ LPU64"\n", *flags, new->l_policy_data.l_flock.pid, mode,
req->l_policy_data.l_flock.start,
req->l_policy_data.l_flock.end);
getlk->fl_end = lock->l_policy_data.l_flock.end;
} else {
/* We need to reprocess the lock to do merges or splits
- * with existing locks owne by this process. */
+ * with existing locks owned by this process. */
flags = LDLM_FL_WAIT_NOREPROC;
ldlm_process_flock_lock(lock, &flags, 1, &err);
}
/* ldlm_request.c */
int ldlm_cancel_lru(struct ldlm_namespace *ns);
+/* ldlm_resource.c */
+void ldlm_resource_insert_lock_after(struct ldlm_lock *original,
+ struct ldlm_lock *new);
+
/* ldlm_lock.c */
void ldlm_grant_lock(struct ldlm_lock *lock, void *data, int datalen,
int run_ast);
lock->l_policy_data.l_extent.end < policy->l_extent.end))
continue;
+ if (lock->l_resource->lr_type == LDLM_EXTENT &&
+ mode == LCK_CW &&
+ lock->l_policy_data.l_extent.gid != policy->l_extent.gid)
+ continue;
+
if (lock->l_destroyed)
continue;
lock->l_policy_data.l_extent.end,
lock->l_req_extent.start, lock->l_req_extent.end);
else if (lock->l_resource->lr_type == LDLM_FLOCK)
- CDEBUG(level, " Pid: %d Extent: "LPU64" -> "LPU64"\n",
+ CDEBUG(level, " Pid: "LPU64" Extent: "LPU64" -> "LPU64"\n",
lock->l_policy_data.l_flock.pid,
lock->l_policy_data.l_flock.start,
lock->l_policy_data.l_flock.end);
lock = list_entry(waiting_locks_list.next, struct ldlm_lock,
l_pending_chain);
- if (lock->l_callback_timeout > jiffies)
+ if ((lock->l_callback_timeout > jiffies) ||
+ (lock->l_req_mode == LCK_CW))
break;
LDLM_ERROR(lock, "lock callback timer expired: evicting client "
l_unlock(&lock->l_resource->lr_namespace->ns_lock);
rc = ptlrpc_queue_wait(req);
- if (rc == -ETIMEDOUT || rc == -EINTR || rc == -ENOTCONN) {
+ if ((rc == -ETIMEDOUT || rc == -EINTR || rc == -ENOTCONN) &&
+ !lock->l_export->exp_libclient) {
ldlm_del_waiting_lock(lock);
ldlm_failed_ast(lock, rc, "completion");
} else if (rc == -EINVAL) {
req->rq_timeout = 2; /* 2 second timeout for initial AST reply */
rc = ptlrpc_queue_wait(req);
- if (rc == -ETIMEDOUT || rc == -EINTR || rc == -ENOTCONN) {
+ if ((rc == -ETIMEDOUT || rc == -EINTR || rc == -ENOTCONN) &&
+ !lock->l_export->exp_libclient) {
ldlm_del_waiting_lock(lock);
ldlm_failed_ast(lock, rc, "glimpse");
} else if (rc == -EINVAL) {
lwd.lwd_lock = lock;
- lwi = LWI_TIMEOUT_INTR(obd_timeout * HZ, ldlm_expired_completion_wait,
- interrupted_completion_wait, &lwd);
+ if (flags & LDLM_FL_NO_TIMEOUT) {
+ LDLM_DEBUG(lock, "waiting indefinitely for group lock\n");
+ lwi = LWI_INTR(interrupted_completion_wait, &lwd);
+ } else {
+ lwi = LWI_TIMEOUT_INTR(obd_timeout * HZ,
+ ldlm_expired_completion_wait,
+ interrupted_completion_wait, &lwd);
+ }
+
if (imp != NULL) {
spin_lock_irqsave(&imp->imp_lock, irqflags);
lwd.lwd_generation = imp->imp_generation;
l_unlock(&res->lr_namespace->ns_lock);
}
+void ldlm_resource_insert_lock_after(struct ldlm_lock *original,
+ struct ldlm_lock *new)
+{
+ struct ldlm_resource *res = original->l_resource;
+
+ l_lock(&res->lr_namespace->ns_lock);
+
+ ldlm_resource_dump(res);
+ CDEBUG(D_OTHER, "About to insert this lock after %p:\n", original);
+ ldlm_lock_dump(D_OTHER, new, 0);
+
+ if (new->l_destroyed) {
+ CDEBUG(D_OTHER, "Lock destroyed, not adding to resource\n");
+ goto out;
+ }
+
+ LASSERT(list_empty(&new->l_res_link));
+
+ list_add(&new->l_res_link, &original->l_res_link);
+ out:
+ l_unlock(&res->lr_namespace->ns_lock);
+}
+
void ldlm_resource_unlink_lock(struct ldlm_lock *lock)
{
l_lock(&lock->l_resource->lr_namespace->ns_lock);
}
fd->fd_flags &= ~O_LOV_DELAY_CREATE;
+ lli->lli_open_flags = flags;
+
out_release:
request = it->d.lustre.it_data;
ptlrpc_req_finished(request);
int rc, valid;
ENTRY;
+ /* clear group lock, if present */
+ if (fd->fd_flags & LL_FILE_CW_LOCKED) {
+ struct lov_stripe_md *lsm = llu_i2info(inode)->lli_smd;
+ fd->fd_flags &= ~(LL_FILE_CW_LOCKED|LL_FILE_IGNORE_LOCK);
+ rc = llu_extent_unlock(fd, inode, lsm, LCK_CW, &fd->fd_cwlockh);
+ }
+
valid = OBD_MD_FLID;
if (test_bit(LLI_F_HAVE_OST_SIZE_LOCK, &lli->lli_flags))
valid |= OBD_MD_FLSIZE | OBD_MD_FLBLOCKS;
struct ll_file_data {
struct obd_client_handle fd_mds_och;
__u32 fd_flags;
+ struct lustre_handle fd_cwlockh;
+ unsigned long fd_gid;
};
struct llu_sb_info
* was opened several times without close, we track an
* open_count here */
struct ll_file_data *lli_file_data;
+ int lli_open_flags;
int lli_open_count;
/* stat FIXME not 64 bit clean */
#include <time.h>
#include <sys/types.h>
#include <sys/queue.h>
+#include <fcntl.h>
#include <sysio.h>
#include <fs.h>
CERROR("ldlm_cli_cancel failed: %d\n", rc);
break;
case LDLM_CB_CANCELING: {
- struct inode *inode = llu_inode_from_lock(lock);
+ struct inode *inode;
struct llu_inode_info *lli;
struct lov_stripe_md *lsm;
__u32 stripe;
__u64 kms;
+ /* This lock wasn't granted, don't try to evict pages */
+ if (lock->l_req_mode != lock->l_granted_mode)
+ RETURN(0);
+
+ inode = llu_inode_from_lock(lock);
if (!inode)
RETURN(0);
lli= llu_i2info(inode);
{
struct ptlrpc_request *req = reqp;
struct inode *inode = llu_inode_from_lock(lock);
- struct obd_export *exp;
struct llu_inode_info *lli;
struct ost_lvb *lvb;
- struct {
- int stripe_number;
- __u64 size;
- struct lov_stripe_md *lsm;
- } data;
- __u32 vallen = sizeof(data);
- int rc, size = sizeof(*lvb);
+ int rc, size = sizeof(*lvb), stripe = 0;
ENTRY;
if (inode == NULL)
- RETURN(0);
+ GOTO(out, rc = -ELDLM_NO_LOCK_DATA);
lli = llu_i2info(inode);
if (lli == NULL)
- goto iput;
+ GOTO(iput, rc = -ELDLM_NO_LOCK_DATA);
if (lli->lli_smd == NULL)
- goto iput;
- exp = llu_i2obdexp(inode);
+ GOTO(iput, rc = -ELDLM_NO_LOCK_DATA);
/* First, find out which stripe index this lock corresponds to. */
if (lli->lli_smd->lsm_stripe_count > 1)
- data.stripe_number = llu_lock_to_stripe_offset(inode, lock);
- else
- data.stripe_number = 0;
-
- data.size = lli->lli_st_size;
- data.lsm = lli->lli_smd;
-
- rc = obd_get_info(exp, strlen("size_to_stripe"), "size_to_stripe",
- &vallen, &data);
- if (rc != 0) {
- CERROR("obd_get_info: rc = %d\n", rc);
- LBUG();
- }
-
- LDLM_DEBUG(lock, "i_size: %Lu -> stripe number %d -> size %Lu",
- lli->lli_st_size, data.stripe_number, data.size);
+ stripe = llu_lock_to_stripe_offset(inode, lock);
rc = lustre_pack_reply(req, 1, &size, NULL);
if (rc) {
CERROR("lustre_pack_reply: %d\n", rc);
- goto iput;
+ GOTO(iput, rc);
}
lvb = lustre_msg_buf(req->rq_repmsg, 0, sizeof(*lvb));
- lvb->lvb_size = data.size;
- ptlrpc_reply(req);
+ lvb->lvb_size = lli->lli_smd->lsm_oinfo[stripe].loi_kms;
+ LDLM_DEBUG(lock, "i_size: %llu -> stripe number %u -> kms "LPU64,
+ lli->lli_st_size, stripe, lvb->lvb_size);
iput:
I_RELE(inode);
- RETURN(0);
+ out:
+ /* These errors are normal races, so we don't want to fill the console
+ * with messages by calling ptlrpc_error() */
+ if (rc == -ELDLM_NO_LOCK_DATA)
+ lustre_pack_reply(req, 0, NULL, NULL);
+
+ req->rq_status = rc;
+ return rc;
}
__u64 lov_merge_size(struct lov_stripe_md *lsm, int kms);
*/
int llu_extent_lock(struct ll_file_data *fd, struct inode *inode,
struct lov_stripe_md *lsm, int mode,
- struct ldlm_extent *extent, struct lustre_handle *lockh)
+ struct ldlm_extent *extent, struct lustre_handle *lockh,
+ int nonblock)
{
struct llu_inode_info *lli = llu_i2info(inode);
struct obd_export *exp = llu_i2obdexp(inode);
struct ldlm_extent size_lock;
struct lustre_handle match_lockh = {0};
int flags, rc, matched;
+ int astflags = nonblock ? LDLM_FL_BLOCK_NOWAIT : 0;
ENTRY;
- rc = llu_extent_lock_no_validate(fd, inode, lsm, mode, extent, lockh, 0);
+ rc = llu_extent_lock_no_validate(fd, inode, lsm, mode, extent,
+ lockh, astflags);
if (rc != ELDLM_OK)
RETURN(rc);
ldlm_policy_data_t policy;
struct llu_sysio_callback_args *lsca;
struct llu_sysio_cookie *cookie;
+ int astflag = (lli->lli_open_flags & O_NONBLOCK) ?
+ LDLM_FL_BLOCK_NOWAIT : 0;
ldlm_error_t err;
int iovidx;
ENTRY;
policy.l_extent.end = pos + count - 1;
err = llu_extent_lock(fd, inode, lsm, LCK_PW, &policy,
- &lockh, 0);
+ &lockh, astflag);
if (err != ELDLM_OK)
GOTO(err_out, err = -ENOLCK);
ldlm_policy_data_t policy;
struct llu_sysio_callback_args *lsca;
struct llu_sysio_cookie *cookie;
+ int astflag = (lli->lli_open_flags & O_NONBLOCK) ?
+ LDLM_FL_BLOCK_NOWAIT : 0;
__u64 kms;
int iovidx;
policy.l_extent.start = pos;
policy.l_extent.end = pos + count - 1;
- err = llu_extent_lock(fd, inode, lsm, LCK_PR, &policy, &lockh, 0);
+ err = llu_extent_lock(fd, inode, lsm, LCK_PR, &policy,
+ &lockh, astflag);
if (err != ELDLM_OK)
GOTO(err_out, err = -ENOLCK);
return -ENOSYS;
}
+static int llu_get_cwlock(struct inode *inode, unsigned long arg)
+{
+ struct llu_inode_info *lli = llu_i2info(inode);
+ struct ll_file_data *fd = lli->lli_file_data;
+ ldlm_policy_data_t policy = { .l_extent = { .start = 0,
+ .end = OBD_OBJECT_EOF}};
+ struct lustre_handle lockh = { 0 };
+ struct lov_stripe_md *lsm = lli->lli_smd;
+ ldlm_error_t err;
+ int flags = 0;
+ ENTRY;
+
+ if (fd->fd_flags & LL_FILE_CW_LOCKED) {
+ RETURN(-EINVAL);
+ }
+
+ policy.l_extent.gid = arg;
+ if (lli->lli_open_flags & O_NONBLOCK)
+ flags = LDLM_FL_BLOCK_NOWAIT;
+
+ err = llu_extent_lock(fd, inode, lsm, LCK_CW, &policy, &lockh, flags);
+ if (err)
+ RETURN(err);
+
+ fd->fd_flags |= LL_FILE_CW_LOCKED|LL_FILE_IGNORE_LOCK;
+ fd->fd_gid = arg;
+ memcpy(&fd->fd_cwlockh, &lockh, sizeof(lockh));
+
+ RETURN(0);
+}
+
+static int llu_put_cwlock(struct inode *inode, unsigned long arg)
+{
+ struct llu_inode_info *lli = llu_i2info(inode);
+ struct ll_file_data *fd = lli->lli_file_data;
+ struct lov_stripe_md *lsm = lli->lli_smd;
+ ldlm_error_t err;
+ ENTRY;
+
+ if (!(fd->fd_flags & LL_FILE_CW_LOCKED))
+ RETURN(-EINVAL);
+
+ if (fd->fd_gid != arg)
+ RETURN(-EINVAL);
+
+ fd->fd_flags &= ~(LL_FILE_CW_LOCKED|LL_FILE_IGNORE_LOCK);
+
+ err = llu_extent_unlock(fd, inode, lsm, LCK_CW, &fd->fd_cwlockh);
+ if (err)
+ RETURN(err);
+
+ fd->fd_gid = 0;
+ memset(&fd->fd_cwlockh, 0, sizeof(fd->fd_cwlockh));
+
+ RETURN(0);
+}
+
static int llu_iop_ioctl(struct inode *ino, unsigned long int request,
va_list ap)
{
- CERROR("liblustre did not support ioctl\n");
+ unsigned long arg;
+
+ switch (request) {
+ case LL_IOC_CW_LOCK:
+ arg = va_arg(ap, unsigned long);
+ return llu_get_cwlock(ino, arg);
+ case LL_IOC_CW_UNLOCK:
+ arg = va_arg(ap, unsigned long);
+ return llu_put_cwlock(ino, arg);
+ }
+
+ CERROR("did not support ioctl cmd %lx\n", request);
return -ENOSYS;
}
int rc, valid;
ENTRY;
+ /* clear group lock, if present */
+ if (fd->fd_flags & LL_FILE_CW_LOCKED) {
+ struct lov_stripe_md *lsm = ll_i2info(inode)->lli_smd;
+ fd->fd_flags &= ~(LL_FILE_CW_LOCKED|LL_FILE_IGNORE_LOCK);
+ rc = ll_extent_unlock(fd, inode, lsm, LCK_CW, &fd->fd_cwlockh);
+ }
+
valid = OBD_MD_FLID;
memset(&obdo, 0, sizeof(obdo));
policy.l_extent.start = *ppos;
policy.l_extent.end = *ppos + count - 1;
- err = ll_extent_lock(fd, inode, lsm, LCK_PR, &policy, &lockh, 0);
+ err = ll_extent_lock(fd, inode, lsm, LCK_PR, &policy, &lockh,
+ (filp->f_flags & O_NONBLOCK)?LDLM_FL_BLOCK_NOWAIT:
+ 0);
if (err != ELDLM_OK)
RETURN(err);
loff_t maxbytes = ll_file_maxbytes(inode);
ldlm_error_t err;
ssize_t retval;
+ int nonblock = 0;
ENTRY;
+ if (file->f_flags & O_NONBLOCK)
+ nonblock = LDLM_FL_BLOCK_NOWAIT;
CDEBUG(D_VFSTRACE, "VFS Op:inode=%lu/%u(%p),size="LPSZ",offset=%Ld\n",
inode->i_ino, inode->i_generation, inode, count, *ppos);
policy.l_extent.end = *ppos + count - 1;
}
- err = ll_extent_lock(fd, inode, lsm, LCK_PW, &policy, &lockh, 0);
+ err = ll_extent_lock(fd, inode, lsm, LCK_PW, &policy, &lockh, nonblock);
if (err != ELDLM_OK)
RETURN(err);
(void *)arg);
}
+static int ll_get_cwlock(struct inode *inode, struct file *file,
+ unsigned long arg)
+{
+ struct ll_file_data *fd = file->private_data;
+ ldlm_policy_data_t policy = { .l_extent = { .start = 0,
+ .end = OBD_OBJECT_EOF}};
+ struct lustre_handle lockh = { 0 };
+ struct ll_inode_info *lli = ll_i2info(inode);
+ struct lov_stripe_md *lsm = lli->lli_smd;
+ ldlm_error_t err;
+ int flags = 0;
+ ENTRY;
+
+ if (fd->fd_flags & LL_FILE_CW_LOCKED) {
+ RETURN(-EINVAL);
+ }
+
+ policy.l_extent.gid = arg;
+ if (file->f_flags & O_NONBLOCK)
+ flags = LDLM_FL_BLOCK_NOWAIT;
+
+ err = ll_extent_lock(fd, inode, lsm, LCK_CW, &policy, &lockh, flags);
+ if (err)
+ RETURN(err);
+
+ fd->fd_flags |= LL_FILE_CW_LOCKED|LL_FILE_IGNORE_LOCK;
+ fd->fd_gid = arg;
+ memcpy(&fd->fd_cwlockh, &lockh, sizeof(lockh));
+
+ RETURN(0);
+}
+
+static int ll_put_cwlock(struct inode *inode, struct file *file,
+ unsigned long arg)
+{
+ struct ll_file_data *fd = file->private_data;
+ struct ll_inode_info *lli = ll_i2info(inode);
+ struct lov_stripe_md *lsm = lli->lli_smd;
+ ldlm_error_t err;
+ ENTRY;
+
+ if (!(fd->fd_flags & LL_FILE_CW_LOCKED)) {
+ /* Ugh, it's already unlocked. */
+ RETURN(-EINVAL);
+ }
+
+ if (fd->fd_gid != arg) /* Ugh? Unlocking with different gid? */
+ RETURN(-EINVAL);
+
+ fd->fd_flags &= ~(LL_FILE_CW_LOCKED|LL_FILE_IGNORE_LOCK);
+
+ err = ll_extent_unlock(fd, inode, lsm, LCK_CW, &fd->fd_cwlockh);
+ if (err)
+ RETURN(err);
+
+ fd->fd_gid = 0;
+ memset(&fd->fd_cwlockh, 0, sizeof(fd->fd_cwlockh));
+
+ RETURN(0);
+}
+
int ll_file_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
unsigned long arg)
{
case EXT3_IOC_GETFLAGS:
case EXT3_IOC_SETFLAGS:
RETURN( ll_iocontrol(inode, file, cmd, arg) );
+ case LL_IOC_CW_LOCK:
+ RETURN(ll_get_cwlock(inode, file, arg));
+ case LL_IOC_CW_UNLOCK:
+ RETURN(ll_put_cwlock(inode, file, arg));
/* We need to special case any other ioctls we want to handle,
* to send them to the MDS/OST as appropriate and to properly
* network encode the arg field.
lprocfs_counter_incr(ll_i2sbi(inode)->ll_stats, LPROC_LL_LLSEEK);
if (origin == 2) { /* SEEK_END */
ldlm_error_t err;
+ int nonblock = 0;
ldlm_policy_data_t policy = { .l_extent = {0, OBD_OBJECT_EOF }};
- err = ll_extent_lock(fd, inode, lsm, LCK_PR, &policy, &lockh,0);
+
+ if (file->f_flags & O_NONBLOCK)
+ nonblock = LDLM_FL_BLOCK_NOWAIT;
+
+ err = ll_extent_lock(fd, inode, lsm, LCK_PR, &policy, &lockh,
+ nonblock);
if (err != ELDLM_OK)
RETURN(err);
LBUG();
}
- CDEBUG(D_DLMTRACE, "inode=%lu, pid=%u, flags=%#x, mode=%u, "
+ CDEBUG(D_DLMTRACE, "inode=%lu, pid="LPU64", flags=%#x, mode=%u, "
"start="LPU64", end="LPU64"\n", inode->i_ino, flock.l_flock.pid,
flags, mode, flock.l_flock.start, flock.l_flock.end);
};
extern kmem_cache_t *ll_file_data_slab;
+struct lustre_handle;
struct ll_file_data {
struct obd_client_handle fd_mds_och;
struct ll_readahead_state fd_ras;
__u32 fd_flags;
+ struct lustre_handle fd_cwlockh;
+ unsigned long fd_gid;
};
-struct lustre_handle;
struct lov_stripe_md;
extern spinlock_t inode_lock;
EXIT;
}
-static int ll_page_matches(struct page *page)
+static int ll_page_matches(struct page *page, int fd_flags)
{
struct lustre_handle match_lockh = {0};
struct inode *inode = page->mapping->host;
int flags, matches;
ENTRY;
+ if (fd_flags & LL_FILE_CW_LOCKED)
+ RETURN(1);
+
page_extent.l_extent.start = (__u64)page->index << PAGE_CACHE_SHIFT;
page_extent.l_extent.end =
page_extent.l_extent.start + PAGE_CACHE_SIZE - 1;
static void ll_readahead(struct ll_readahead_state *ras,
struct obd_export *exp, struct address_space *mapping,
- struct obd_io_group *oig)
+ struct obd_io_group *oig, int flags)
{
unsigned long i, start, end;
struct ll_async_page *llap;
if (Page_Uptodate(page))
goto next_page;
- if ((rc = ll_page_matches(page)) <= 0) {
+ if ((rc = ll_page_matches(page, flags)) <= 0) {
LL_CDEBUG_PAGE(D_READA | D_PAGE, page,
"lock match failed: rc %d\n", rc);
goto next_page;
if (llap->llap_defer_uptodate) {
ll_readahead_update(inode, &fd->fd_ras, page->index, 1);
- ll_readahead(&fd->fd_ras, exp, page->mapping, oig);
+ ll_readahead(&fd->fd_ras, exp, page->mapping, oig,fd->fd_flags);
obd_trigger_group_io(exp, ll_i2info(inode)->lli_smd, NULL,
oig);
LL_CDEBUG_PAGE(D_PAGE, page, "marking uptodate from defer\n");
ll_readahead_update(inode, &fd->fd_ras, page->index, 0);
- rc = ll_page_matches(page);
+ rc = ll_page_matches(page, fd->fd_flags);
if (rc < 0) {
LL_CDEBUG_PAGE(D_ERROR, page, "lock match failed: rc %d\n", rc);
GOTO(out, rc);
LL_CDEBUG_PAGE(D_PAGE, page, "queued readpage\n");
if ((ll_i2sbi(inode)->ll_flags & LL_SBI_READAHEAD))
- ll_readahead(&fd->fd_ras, exp, page->mapping, oig);
+ ll_readahead(&fd->fd_ras, exp, page->mapping, oig,fd->fd_flags);
rc = obd_trigger_group_io(exp, ll_i2info(inode)->lli_smd, NULL, oig);
&sub_ext.l_extent.end))
continue;
+ sub_ext.l_extent.gid = policy->l_extent.gid;
+
if (lov->tgts[loi->loi_ost_idx].active == 0) {
CDEBUG(D_HA, "lov idx %d inactive\n", loi->loi_ost_idx);
continue;
{
ENTRY;
- ldlm_lock_decref(lockh, mode);
+ if (mode == LCK_CW)
+ ldlm_lock_decref_and_cancel(lockh, mode);
+ else
+ ldlm_lock_decref(lockh, mode);
RETURN(0);
}
void lustre_swab_ldlm_policy_data (ldlm_policy_data_t *d)
{
- /* the lock data is a union and the first two fields are always an
- * extent so it's ok to process an LDLM_EXTENT and LDLM_FLOCK lock
- * data the same way. */
+ /* the lock data is a union and the first three fields of both EXTENT
+ * and FLOCK types are __u64, so it's ok to swab them in the same way */
__swab64s (&d->l_flock.start);
__swab64s (&d->l_flock.end);
- __swab32s (&d->l_flock.pid);
+ __swab64s (&d->l_flock.pid);
+ __swab64s (&d->l_flock.blocking_pid);
}
void lustre_swab_ldlm_intent (struct ldlm_intent *i)
(long long)(int)sizeof(((struct ldlm_res_id *)0)->name[4]));
/* Checks for struct ldlm_extent */
- LASSERTF((int)sizeof(struct ldlm_extent) == 16, " found %lld\n",
+ LASSERTF((int)sizeof(struct ldlm_extent) == 24, " found %lld\n",
(long long)(int)sizeof(struct ldlm_extent));
LASSERTF(offsetof(struct ldlm_extent, start) == 0, " found %lld\n",
(long long)offsetof(struct ldlm_extent, start));
(long long)offsetof(struct ldlm_extent, end));
LASSERTF((int)sizeof(((struct ldlm_extent *)0)->end) == 8, " found %lld\n",
(long long)(int)sizeof(((struct ldlm_extent *)0)->end));
+ LASSERTF(offsetof(struct ldlm_extent, gid) == 16, " found %lld\n",
+ (long long)offsetof(struct ldlm_extent, gid));
+ LASSERTF((int)sizeof(((struct ldlm_extent *)0)->gid) == 8, " found %lld\n",
+ (long long)(int)sizeof(((struct ldlm_extent *)0)->gid));
/* Checks for struct ldlm_flock */
- LASSERTF((int)sizeof(struct ldlm_flock) == 32, " found %lld\n",
+ LASSERTF((int)sizeof(struct ldlm_flock) == 40, " found %lld\n",
(long long)(int)sizeof(struct ldlm_flock));
LASSERTF(offsetof(struct ldlm_flock, start) == 0, " found %lld\n",
(long long)offsetof(struct ldlm_flock, start));
(long long)offsetof(struct ldlm_flock, end));
LASSERTF((int)sizeof(((struct ldlm_flock *)0)->end) == 8, " found %lld\n",
(long long)(int)sizeof(((struct ldlm_flock *)0)->end));
- LASSERTF(offsetof(struct ldlm_flock, blocking_export) == 16, " found %lld\n",
- (long long)offsetof(struct ldlm_flock, blocking_export));
- LASSERTF((int)sizeof(((struct ldlm_flock *)0)->blocking_export) == 8, " found %lld\n",
- (long long)(int)sizeof(((struct ldlm_flock *)0)->blocking_export));
+ LASSERTF(offsetof(struct ldlm_flock, pid) == 16, " found %lld\n",
+ (long long)offsetof(struct ldlm_flock, pid));
+ LASSERTF((int)sizeof(((struct ldlm_flock *)0)->pid) == 8, " found %lld\n",
+ (long long)(int)sizeof(((struct ldlm_flock *)0)->pid));
LASSERTF(offsetof(struct ldlm_flock, blocking_pid) == 24, " found %lld\n",
(long long)offsetof(struct ldlm_flock, blocking_pid));
- LASSERTF((int)sizeof(((struct ldlm_flock *)0)->blocking_pid) == 4, " found %lld\n",
+ LASSERTF((int)sizeof(((struct ldlm_flock *)0)->blocking_pid) == 8, " found %lld\n",
(long long)(int)sizeof(((struct ldlm_flock *)0)->blocking_pid));
- LASSERTF(offsetof(struct ldlm_flock, pid) == 28, " found %lld\n",
- (long long)offsetof(struct ldlm_flock, pid));
- LASSERTF((int)sizeof(((struct ldlm_flock *)0)->pid) == 4, " found %lld\n",
- (long long)(int)sizeof(((struct ldlm_flock *)0)->pid));
+ LASSERTF(offsetof(struct ldlm_flock, blocking_export) == 32, " found %lld\n",
+ (long long)offsetof(struct ldlm_flock, blocking_export));
+ LASSERTF((int)sizeof(((struct ldlm_flock *)0)->blocking_export) == 8, " found %lld\n",
+ (long long)(int)sizeof(((struct ldlm_flock *)0)->blocking_export));
/* Checks for struct ldlm_intent */
LASSERTF((int)sizeof(struct ldlm_intent) == 8, " found %lld\n",
CHECK_STRUCT(ldlm_extent);
CHECK_MEMBER(ldlm_extent, start);
CHECK_MEMBER(ldlm_extent, end);
+ CHECK_MEMBER(ldlm_extent, gid);
}
void
void lustre_assert_wire_constants(void)
{
/* Wire protocol assertions generated by 'wirecheck'
- * running on Linux schnapps.adilger.int 2.4.22-l32 #4 Thu Jan 8 14:32:57 MST 2004 i686 i686
+ * running on Linux innova.tion.org 2.4.20-30.9-87k.37-b1_2.RC_1_2_0_3.200403111837 #1 Thu Ma
* with gcc version 3.2.2 20030222 (Red Hat Linux 3.2.2-5) */
(long long)(int)sizeof(((struct ldlm_res_id *)0)->name[4]));
/* Checks for struct ldlm_extent */
- LASSERTF((int)sizeof(struct ldlm_extent) == 16, " found %lld\n",
+ LASSERTF((int)sizeof(struct ldlm_extent) == 24, " found %lld\n",
(long long)(int)sizeof(struct ldlm_extent));
LASSERTF(offsetof(struct ldlm_extent, start) == 0, " found %lld\n",
(long long)offsetof(struct ldlm_extent, start));
(long long)offsetof(struct ldlm_extent, end));
LASSERTF((int)sizeof(((struct ldlm_extent *)0)->end) == 8, " found %lld\n",
(long long)(int)sizeof(((struct ldlm_extent *)0)->end));
+ LASSERTF(offsetof(struct ldlm_extent, gid) == 16, " found %lld\n",
+ (long long)offsetof(struct ldlm_extent, gid));
+ LASSERTF((int)sizeof(((struct ldlm_extent *)0)->gid) == 8, " found %lld\n",
+ (long long)(int)sizeof(((struct ldlm_extent *)0)->gid));
/* Checks for struct ldlm_flock */
- LASSERTF((int)sizeof(struct ldlm_flock) == 32, " found %lld\n",
+ LASSERTF((int)sizeof(struct ldlm_flock) == 40, " found %lld\n",
(long long)(int)sizeof(struct ldlm_flock));
LASSERTF(offsetof(struct ldlm_flock, start) == 0, " found %lld\n",
(long long)offsetof(struct ldlm_flock, start));
(long long)offsetof(struct ldlm_flock, end));
LASSERTF((int)sizeof(((struct ldlm_flock *)0)->end) == 8, " found %lld\n",
(long long)(int)sizeof(((struct ldlm_flock *)0)->end));
- LASSERTF(offsetof(struct ldlm_flock, blocking_export) == 16, " found %lld\n",
+ LASSERTF(offsetof(struct ldlm_flock, blocking_export) == 32, " found %lld\n",
(long long)offsetof(struct ldlm_flock, blocking_export));
LASSERTF((int)sizeof(((struct ldlm_flock *)0)->blocking_export) == 8, " found %lld\n",
(long long)(int)sizeof(((struct ldlm_flock *)0)->blocking_export));
LASSERTF(offsetof(struct ldlm_flock, blocking_pid) == 24, " found %lld\n",
(long long)offsetof(struct ldlm_flock, blocking_pid));
- LASSERTF((int)sizeof(((struct ldlm_flock *)0)->blocking_pid) == 4, " found %lld\n",
+ LASSERTF((int)sizeof(((struct ldlm_flock *)0)->blocking_pid) == 8, " found %lld\n",
(long long)(int)sizeof(((struct ldlm_flock *)0)->blocking_pid));
- LASSERTF(offsetof(struct ldlm_flock, pid) == 28, " found %lld\n",
+ LASSERTF(offsetof(struct ldlm_flock, pid) == 16, " found %lld\n",
(long long)offsetof(struct ldlm_flock, pid));
- LASSERTF((int)sizeof(((struct ldlm_flock *)0)->pid) == 4, " found %lld\n",
+ LASSERTF((int)sizeof(((struct ldlm_flock *)0)->pid) == 8, " found %lld\n",
(long long)(int)sizeof(((struct ldlm_flock *)0)->pid));
/* Checks for struct ldlm_intent */
(long long)(int)sizeof(((struct ldlm_resource_desc *)0)->lr_name));
/* Checks for struct ldlm_lock_desc */
- LASSERTF((int)sizeof(struct ldlm_lock_desc) == 80, " found %lld\n",
+ LASSERTF((int)sizeof(struct ldlm_lock_desc) == 88, " found %lld\n",
(long long)(int)sizeof(struct ldlm_lock_desc));
LASSERTF(offsetof(struct ldlm_lock_desc, l_resource) == 0, " found %lld\n",
(long long)offsetof(struct ldlm_lock_desc, l_resource));
(long long)(int)sizeof(((struct ldlm_lock_desc *)0)->l_granted_mode));
LASSERTF(offsetof(struct ldlm_lock_desc, l_policy_data) == 48, " found %lld\n",
(long long)offsetof(struct ldlm_lock_desc, l_policy_data));
- LASSERTF((int)sizeof(((struct ldlm_lock_desc *)0)->l_policy_data) == 32, " found %lld\n",
+ LASSERTF((int)sizeof(((struct ldlm_lock_desc *)0)->l_policy_data) == 40, " found %lld\n",
(long long)(int)sizeof(((struct ldlm_lock_desc *)0)->l_policy_data));
/* Checks for struct ldlm_request */
- LASSERTF((int)sizeof(struct ldlm_request) == 104, " found %lld\n",
+ LASSERTF((int)sizeof(struct ldlm_request) == 112, " found %lld\n",
(long long)(int)sizeof(struct ldlm_request));
LASSERTF(offsetof(struct ldlm_request, lock_flags) == 0, " found %lld\n",
(long long)offsetof(struct ldlm_request, lock_flags));
(long long)(int)sizeof(((struct ldlm_request *)0)->lock_flags));
LASSERTF(offsetof(struct ldlm_request, lock_desc) == 8, " found %lld\n",
(long long)offsetof(struct ldlm_request, lock_desc));
- LASSERTF((int)sizeof(((struct ldlm_request *)0)->lock_desc) == 80, " found %lld\n",
+ LASSERTF((int)sizeof(((struct ldlm_request *)0)->lock_desc) == 88, " found %lld\n",
(long long)(int)sizeof(((struct ldlm_request *)0)->lock_desc));
- LASSERTF(offsetof(struct ldlm_request, lock_handle1) == 88, " found %lld\n",
+ LASSERTF(offsetof(struct ldlm_request, lock_handle1) == 96, " found %lld\n",
(long long)offsetof(struct ldlm_request, lock_handle1));
LASSERTF((int)sizeof(((struct ldlm_request *)0)->lock_handle1) == 8, " found %lld\n",
(long long)(int)sizeof(((struct ldlm_request *)0)->lock_handle1));
- LASSERTF(offsetof(struct ldlm_request, lock_handle2) == 96, " found %lld\n",
+ LASSERTF(offsetof(struct ldlm_request, lock_handle2) == 104, " found %lld\n",
(long long)offsetof(struct ldlm_request, lock_handle2));
LASSERTF((int)sizeof(((struct ldlm_request *)0)->lock_handle2) == 8, " found %lld\n",
(long long)(int)sizeof(((struct ldlm_request *)0)->lock_handle2));
/* Checks for struct ldlm_reply */
- LASSERTF((int)sizeof(struct ldlm_reply) == 112, " found %lld\n",
+ LASSERTF((int)sizeof(struct ldlm_reply) == 120, " found %lld\n",
(long long)(int)sizeof(struct ldlm_reply));
LASSERTF(offsetof(struct ldlm_reply, lock_flags) == 0, " found %lld\n",
(long long)offsetof(struct ldlm_reply, lock_flags));
(long long)(int)sizeof(((struct ldlm_reply *)0)->lock_flags));
LASSERTF(offsetof(struct ldlm_request, lock_desc) == 8, " found %lld\n",
(long long)offsetof(struct ldlm_request, lock_desc));
- LASSERTF((int)sizeof(((struct ldlm_request *)0)->lock_desc) == 80, " found %lld\n",
+ LASSERTF((int)sizeof(((struct ldlm_request *)0)->lock_desc) == 88, " found %lld\n",
(long long)(int)sizeof(((struct ldlm_request *)0)->lock_desc));
- LASSERTF(offsetof(struct ldlm_reply, lock_handle) == 88, " found %lld\n",
+ LASSERTF(offsetof(struct ldlm_reply, lock_handle) == 96, " found %lld\n",
(long long)offsetof(struct ldlm_reply, lock_handle));
LASSERTF((int)sizeof(((struct ldlm_reply *)0)->lock_handle) == 8, " found %lld\n",
(long long)(int)sizeof(((struct ldlm_reply *)0)->lock_handle));
- LASSERTF(offsetof(struct ldlm_reply, lock_policy_res1) == 96, " found %lld\n",
+ LASSERTF(offsetof(struct ldlm_reply, lock_policy_res1) == 104, " found %lld\n",
(long long)offsetof(struct ldlm_reply, lock_policy_res1));
LASSERTF((int)sizeof(((struct ldlm_reply *)0)->lock_policy_res1) == 8, " found %lld\n",
(long long)(int)sizeof(((struct ldlm_reply *)0)->lock_policy_res1));
- LASSERTF(offsetof(struct ldlm_reply, lock_policy_res2) == 104, " found %lld\n",
+ LASSERTF(offsetof(struct ldlm_reply, lock_policy_res2) == 112, " found %lld\n",
(long long)offsetof(struct ldlm_reply, lock_policy_res2));
LASSERTF((int)sizeof(((struct ldlm_reply *)0)->lock_policy_res2) == 8, " found %lld\n",
(long long)(int)sizeof(((struct ldlm_reply *)0)->lock_policy_res2));