void unlock_res_and_lock(struct ldlm_lock *lock) { /* on server-side resource of lock doesn't change */ unlock_res(lock->l_resource); if (!lock->l_ns_srv) cfs_spin_unlock(&lock->l_lock); }
/** * Unlock a lock and its resource previously locked with lock_res_and_lock */ void unlock_res_and_lock(struct ldlm_lock *lock) { /* on server-side resource of lock doesn't change */ ldlm_clear_res_locked(lock); unlock_res(lock->l_resource); spin_unlock(&lock->l_lock); }
/** * Process a granting attempt for plain lock. * Must be called with ns lock held. * * This function looks for any conflicts for \a lock in the granted or * waiting queues. The lock is granted if no conflicts are found in * either queue. * * If \a first_enq is 0 (ie, called from ldlm_reprocess_queue): * - blocking ASTs have already been sent * * If \a first_enq is 1 (ie, called from ldlm_lock_enqueue): * - blocking ASTs have not been sent yet, so list of conflicting locks * would be collected and ASTs sent. */ int ldlm_process_plain_lock(struct ldlm_lock *lock, __u64 *flags, int first_enq, ldlm_error_t *err, struct list_head *work_list) { struct ldlm_resource *res = lock->l_resource; struct list_head rpc_list; int rc; ENTRY; LASSERT(lock->l_granted_mode != lock->l_req_mode); check_res_locked(res); LASSERT(list_empty(&res->lr_converting)); INIT_LIST_HEAD(&rpc_list); if (!first_enq) { LASSERT(work_list != NULL); rc = ldlm_plain_compat_queue(&res->lr_granted, lock, NULL); if (!rc) RETURN(LDLM_ITER_STOP); rc = ldlm_plain_compat_queue(&res->lr_waiting, lock, NULL); if (!rc) RETURN(LDLM_ITER_STOP); ldlm_resource_unlink_lock(lock); ldlm_grant_lock(lock, work_list); RETURN(LDLM_ITER_CONTINUE); } restart: rc = ldlm_plain_compat_queue(&res->lr_granted, lock, &rpc_list); rc += ldlm_plain_compat_queue(&res->lr_waiting, lock, &rpc_list); if (rc != 2) { /* If either of the compat_queue()s returned 0, 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 * terrible folly -- if we goto restart, we could get * re-ordered! Causes deadlock, because ASTs aren't sent! */ if (list_empty(&lock->l_res_link)) ldlm_resource_add_lock(res, &res->lr_waiting, lock); unlock_res(res); rc = ldlm_run_ast_work(ldlm_res_to_ns(res), &rpc_list, LDLM_WORK_BL_AST); lock_res(res); if (rc == -ERESTART) GOTO(restart, rc); *flags |= LDLM_FL_BLOCK_GRANTED; } else { ldlm_resource_unlink_lock(lock); ldlm_grant_lock(lock, NULL); } RETURN(0); }
/** * Implementation of ldlm_valblock_ops::lvbo_fill for OFD. * * This function is called to fill the given RPC buffer \a buf with LVB data * * \param[in] lock LDLM lock * \param[in] buf RPC buffer to fill * \param[in] buflen buffer length * * \retval size of LVB data written into \a buf buffer */ static int ofd_lvbo_fill(struct ldlm_lock *lock, void *buf, int buflen) { struct ldlm_resource *res = lock->l_resource; int lvb_len; /* Former lvbo_init not allocate the "LVB". */ if (unlikely(res->lr_lvb_len == 0)) return 0; lvb_len = ofd_lvbo_size(lock); LASSERT(lvb_len <= res->lr_lvb_len); if (lvb_len > buflen) lvb_len = buflen; lock_res(res); memcpy(buf, res->lr_lvb_data, lvb_len); unlock_res(res); return lvb_len; }
/** * Implementation of ldlm_valblock_ops::lvbo_update for OFD. * * When a client generates a glimpse enqueue, it wants to get the current * file size and updated attributes for a stat() type operation, but these * attributes may be writeback cached on another client. The client with * the DLM extent lock at the highest offset is asked for its current * attributes via a glimpse callback on its extent lock, on the assumption * that it has the highest file size and the newest timestamps. The timestamps * are guaranteed to be correct if there is only a single writer on the file, * but may be slightly inaccurate if there are multiple concurrent writers on * the same object. In order to avoid race conditions between the glimpse AST * and the client cancelling the lock, ofd_lvbo_update() also updates * the attributes from the local object. If the last client hasn't done any * writes yet, or has already written its data and cancelled its lock before * it processed the glimpse, then the local inode will have more uptodate * information. * * This is called in two ways: * \a req != NULL : called by the DLM itself after a glimpse callback * \a req == NULL : called by the OFD after a disk write * * \param[in] res LDLM resource * \param[in] req PTLRPC request * \param[in] increase_only don't allow LVB values to decrease * * \retval 0 on successful setup * \retval negative value on error */ static int ofd_lvbo_update(struct ldlm_resource *res, struct ptlrpc_request *req, int increase_only) { struct ofd_device *ofd; struct ofd_object *fo; struct ofd_thread_info *info; struct ost_lvb *lvb; struct lu_env env; int rc = 0; ENTRY; LASSERT(res != NULL); ofd = ldlm_res_to_ns(res)->ns_lvbp; LASSERT(ofd != NULL); rc = lu_env_init(&env, LCT_DT_THREAD); if (rc) RETURN(rc); info = ofd_info_init(&env, NULL); fid_extract_from_res_name(&info->fti_fid, &res->lr_name); lvb = res->lr_lvb_data; if (lvb == NULL) { CERROR("%s: no LVB data for "DFID"\n", ofd_name(ofd), PFID(&info->fti_fid)); GOTO(out_env, rc = 0); } /* Update the LVB from the network message */ if (req != NULL) { struct ost_lvb *rpc_lvb; bool lvb_type; if (req->rq_import != NULL) lvb_type = imp_connect_lvb_type(req->rq_import); else lvb_type = exp_connect_lvb_type(req->rq_export); if (!lvb_type) { struct ost_lvb_v1 *lvb_v1; lvb_v1 = req_capsule_server_swab_get(&req->rq_pill, &RMF_DLM_LVB, lustre_swab_ost_lvb_v1); if (lvb_v1 == NULL) goto disk_update; rpc_lvb = &info->fti_lvb; memcpy(rpc_lvb, lvb_v1, sizeof *lvb_v1); rpc_lvb->lvb_mtime_ns = 0; rpc_lvb->lvb_atime_ns = 0; rpc_lvb->lvb_ctime_ns = 0; } else { rpc_lvb = req_capsule_server_swab_get(&req->rq_pill, &RMF_DLM_LVB, lustre_swab_ost_lvb); if (rpc_lvb == NULL) goto disk_update; } lock_res(res); if (rpc_lvb->lvb_size > lvb->lvb_size || !increase_only) { CDEBUG(D_DLMTRACE, "res: "DFID" updating lvb size: " LPU64" -> "LPU64"\n", PFID(&info->fti_fid), lvb->lvb_size, rpc_lvb->lvb_size); lvb->lvb_size = rpc_lvb->lvb_size; } if (rpc_lvb->lvb_mtime > lvb->lvb_mtime || !increase_only) { CDEBUG(D_DLMTRACE, "res: "DFID" updating lvb mtime: " LPU64" -> "LPU64"\n", PFID(&info->fti_fid), lvb->lvb_mtime, rpc_lvb->lvb_mtime); lvb->lvb_mtime = rpc_lvb->lvb_mtime; } if (rpc_lvb->lvb_atime > lvb->lvb_atime || !increase_only) { CDEBUG(D_DLMTRACE, "res: "DFID" updating lvb atime: " LPU64" -> "LPU64"\n", PFID(&info->fti_fid), lvb->lvb_atime, rpc_lvb->lvb_atime); lvb->lvb_atime = rpc_lvb->lvb_atime; } if (rpc_lvb->lvb_ctime > lvb->lvb_ctime || !increase_only) { CDEBUG(D_DLMTRACE, "res: "DFID" updating lvb ctime: " LPU64" -> "LPU64"\n", PFID(&info->fti_fid), lvb->lvb_ctime, rpc_lvb->lvb_ctime); lvb->lvb_ctime = rpc_lvb->lvb_ctime; } if (rpc_lvb->lvb_blocks > lvb->lvb_blocks || !increase_only) { CDEBUG(D_DLMTRACE, "res: "DFID" updating lvb blocks: " LPU64" -> "LPU64"\n", PFID(&info->fti_fid), lvb->lvb_blocks, rpc_lvb->lvb_blocks); lvb->lvb_blocks = rpc_lvb->lvb_blocks; } unlock_res(res); } disk_update: /* Update the LVB from the disk inode */ ost_fid_from_resid(&info->fti_fid, &res->lr_name, ofd->ofd_lut.lut_lsd.lsd_osd_index); fo = ofd_object_find(&env, ofd, &info->fti_fid); if (IS_ERR(fo)) GOTO(out_env, rc = PTR_ERR(fo)); rc = ofd_attr_get(&env, fo, &info->fti_attr); if (rc) GOTO(out_obj, rc); lock_res(res); if (info->fti_attr.la_size > lvb->lvb_size || !increase_only) { CDEBUG(D_DLMTRACE, "res: "DFID" updating lvb size from disk: " LPU64" -> %llu\n", PFID(&info->fti_fid), lvb->lvb_size, info->fti_attr.la_size); lvb->lvb_size = info->fti_attr.la_size; } if (info->fti_attr.la_mtime >lvb->lvb_mtime || !increase_only) { CDEBUG(D_DLMTRACE, "res: "DFID" updating lvb mtime from disk: " LPU64" -> "LPU64"\n", PFID(&info->fti_fid), lvb->lvb_mtime, info->fti_attr.la_mtime); lvb->lvb_mtime = info->fti_attr.la_mtime; } if (info->fti_attr.la_atime >lvb->lvb_atime || !increase_only) { CDEBUG(D_DLMTRACE, "res: "DFID" updating lvb atime from disk: " LPU64" -> "LPU64"\n", PFID(&info->fti_fid), lvb->lvb_atime, info->fti_attr.la_atime); lvb->lvb_atime = info->fti_attr.la_atime; } if (info->fti_attr.la_ctime >lvb->lvb_ctime || !increase_only) { CDEBUG(D_DLMTRACE, "res: "DFID" updating lvb ctime from disk: " LPU64" -> "LPU64"\n", PFID(&info->fti_fid), lvb->lvb_ctime, info->fti_attr.la_ctime); lvb->lvb_ctime = info->fti_attr.la_ctime; } if (info->fti_attr.la_blocks > lvb->lvb_blocks || !increase_only) { CDEBUG(D_DLMTRACE, "res: "DFID" updating lvb blocks from disk: " LPU64" -> %llu\n", PFID(&info->fti_fid), lvb->lvb_blocks, (unsigned long long)info->fti_attr.la_blocks); lvb->lvb_blocks = info->fti_attr.la_blocks; } unlock_res(res); out_obj: ofd_object_put(&env, fo); out_env: lu_env_fini(&env); return rc; }