1 /* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
2 * vim:expandtab:shiftwidth=8:tabstop=8:
5 * Memory Descriptor management routines
7 * Copyright (c) 2001-2003 Cluster File Systems, Inc.
9 * This file is part of Lustre, http://www.lustre.org
11 * Lustre is free software; you can redistribute it and/or
12 * modify it under the terms of version 2 of the GNU General Public
13 * License as published by the Free Software Foundation.
15 * Lustre is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
20 * You should have received a copy of the GNU General Public License
21 * along with Lustre; if not, write to the Free Software
22 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
25 #define DEBUG_SUBSYSTEM S_PORTALS
30 # include <libcfs/kp30.h>
33 #include <portals/lib-p30.h>
35 /* must be called with state lock held */
37 lib_md_unlink(lib_nal_t *nal, lib_md_t *md)
39 if ((md->md_flags & PTL_MD_FLAG_ZOMBIE) == 0) {
40 /* first unlink attempt... */
41 lib_me_t *me = md->me;
43 md->md_flags |= PTL_MD_FLAG_ZOMBIE;
45 /* Disassociate from ME (if any), and unlink it if it was created
49 if (me->unlink == PTL_UNLINK)
50 lib_me_unlink(nal, me);
53 /* emsure all future handle lookups fail */
54 lib_invalidate_handle(nal, &md->md_lh);
57 if (md->pending != 0) {
58 CDEBUG(D_NET, "Queueing unlink of md %p\n", md);
62 CDEBUG(D_NET, "Unlinking md %p\n", md);
64 if ((md->options & PTL_MD_KIOV) != 0) {
65 if (nal->libnal_unmap_pages != NULL)
66 nal->libnal_unmap_pages (nal,
70 } else if (nal->libnal_unmap != NULL) {
71 nal->libnal_unmap (nal,
72 md->md_niov, md->md_iov.iov,
77 md->eq->eq_refcount--;
78 LASSERT (md->eq->eq_refcount >= 0);
81 list_del (&md->md_list);
85 /* must be called with state lock held */
87 lib_md_build(lib_nal_t *nal, lib_md_t *lmd, ptl_md_t *umd, int unlink)
95 /* NB we are passed an allocated, but uninitialised/active md.
96 * if we return success, caller may lib_md_unlink() it.
97 * otherwise caller may only lib_md_free() it.
100 if (!PtlHandleIsEqual (umd->eq_handle, PTL_EQ_NONE)) {
101 eq = ptl_handle2eq(&umd->eq_handle, nal);
103 return PTL_EQ_INVALID;
106 /* This implementation doesn't know how to create START events or
107 * disable END events. Best to LASSERT our caller is compliant so
108 * we find out quickly... */
109 LASSERT (eq == NULL ||
110 ((umd->options & PTL_MD_EVENT_START_DISABLE) != 0 &&
111 (umd->options & PTL_MD_EVENT_END_DISABLE) == 0));
114 lmd->start = umd->start;
116 lmd->max_size = umd->max_size;
117 lmd->options = umd->options;
118 lmd->user_ptr = umd->user_ptr;
120 lmd->threshold = umd->threshold;
122 lmd->md_flags = (unlink == PTL_UNLINK) ? PTL_MD_FLAG_AUTO_UNLINK : 0;
124 if ((umd->options & PTL_MD_IOVEC) != 0) {
126 if ((umd->options & PTL_MD_KIOV) != 0) /* Can't specify both */
127 return PTL_MD_ILLEGAL;
129 lmd->md_niov = niov = umd->length;
130 memcpy(lmd->md_iov.iov, umd->start,
131 niov * sizeof (lmd->md_iov.iov[0]));
133 for (i = 0; i < niov; i++) {
134 /* We take the base address on trust */
135 if (lmd->md_iov.iov[i].iov_len <= 0) /* invalid length */
136 return PTL_MD_ILLEGAL;
138 total_length += lmd->md_iov.iov[i].iov_len;
141 lmd->length = total_length;
143 if ((umd->options & PTL_MD_MAX_SIZE) != 0 && /* max size used */
144 (umd->max_size < 0 ||
145 umd->max_size > total_length)) // illegal max_size
146 return PTL_MD_ILLEGAL;
148 if (nal->libnal_map != NULL) {
149 rc = nal->libnal_map (nal, niov, lmd->md_iov.iov,
154 } else if ((umd->options & PTL_MD_KIOV) != 0) {
156 return PTL_MD_ILLEGAL;
158 /* Trap attempt to use paged I/O if unsupported early. */
159 if (nal->libnal_send_pages == NULL ||
160 nal->libnal_recv_pages == NULL)
161 return PTL_MD_INVALID;
163 lmd->md_niov = niov = umd->length;
164 memcpy(lmd->md_iov.kiov, umd->start,
165 niov * sizeof (lmd->md_iov.kiov[0]));
167 for (i = 0; i < niov; i++) {
168 /* We take the page pointer on trust */
169 if (lmd->md_iov.kiov[i].kiov_offset +
170 lmd->md_iov.kiov[i].kiov_len > PAGE_SIZE )
171 return PTL_VAL_FAILED; /* invalid length */
173 total_length += lmd->md_iov.kiov[i].kiov_len;
176 lmd->length = total_length;
178 if ((umd->options & PTL_MD_MAX_SIZE) != 0 && /* max size used */
179 (umd->max_size < 0 ||
180 umd->max_size > total_length)) // illegal max_size
181 return PTL_MD_ILLEGAL;
183 if (nal->libnal_map_pages != NULL) {
184 rc = nal->libnal_map_pages (nal, niov, lmd->md_iov.kiov,
190 } else { /* contiguous */
191 lmd->length = umd->length;
192 lmd->md_niov = niov = 1;
193 lmd->md_iov.iov[0].iov_base = umd->start;
194 lmd->md_iov.iov[0].iov_len = umd->length;
196 if ((umd->options & PTL_MD_MAX_SIZE) != 0 && /* max size used */
197 (umd->max_size < 0 ||
198 umd->max_size > umd->length)) // illegal max_size
199 return PTL_MD_ILLEGAL;
201 if (nal->libnal_map != NULL) {
202 rc = nal->libnal_map (nal, niov, lmd->md_iov.iov,
212 /* It's good; let handle2md succeed and add to active mds */
213 lib_initialise_handle (nal, &lmd->md_lh, PTL_COOKIE_TYPE_MD);
214 list_add (&lmd->md_list, &nal->libnal_ni.ni_active_mds);
219 /* must be called with state lock held */
221 lib_md_deconstruct(lib_nal_t *nal, lib_md_t *lmd, ptl_md_t *umd)
223 /* NB this doesn't copy out all the iov entries so when a
224 * discontiguous MD is copied out, the target gets to know the
225 * original iov pointer (in start) and the number of entries it had
228 umd->start = lmd->start;
229 umd->length = ((lmd->options & (PTL_MD_IOVEC | PTL_MD_KIOV)) == 0) ?
230 lmd->length : lmd->md_niov;
231 umd->threshold = lmd->threshold;
232 umd->max_size = lmd->max_size;
233 umd->options = lmd->options;
234 umd->user_ptr = lmd->user_ptr;
235 ptl_eq2handle(&umd->eq_handle, nal, lmd->eq);
239 lib_api_md_attach(nal_t *apinal, ptl_handle_me_t *meh,
240 ptl_md_t *umd, ptl_unlink_t unlink,
241 ptl_handle_md_t *handle)
243 lib_nal_t *nal = apinal->nal_data;
249 if ((umd->options & (PTL_MD_KIOV | PTL_MD_IOVEC)) != 0 &&
250 umd->length > PTL_MD_MAX_IOV) /* too many fragments */
251 return PTL_IOV_INVALID;
253 md = lib_md_alloc(nal, umd);
257 LIB_LOCK(nal, flags);
259 me = ptl_handle2me(meh, nal);
262 } else if (me->md != NULL) {
265 rc = lib_md_build(nal, md, umd, unlink);
270 ptl_md2handle(handle, nal, md);
272 LIB_UNLOCK(nal, flags);
277 lib_md_free (nal, md);
279 LIB_UNLOCK(nal, flags);
284 lib_api_md_bind(nal_t *apinal,
285 ptl_md_t *umd, ptl_unlink_t unlink,
286 ptl_handle_md_t *handle)
288 lib_nal_t *nal = apinal->nal_data;
293 if ((umd->options & (PTL_MD_KIOV | PTL_MD_IOVEC)) != 0 &&
294 umd->length > PTL_MD_MAX_IOV) /* too many fragments */
295 return PTL_IOV_INVALID;
297 md = lib_md_alloc(nal, umd);
301 LIB_LOCK(nal, flags);
303 rc = lib_md_build(nal, md, umd, unlink);
306 ptl_md2handle(handle, nal, md);
308 LIB_UNLOCK(nal, flags);
312 lib_md_free (nal, md);
314 LIB_UNLOCK(nal, flags);
319 lib_api_md_unlink (nal_t *apinal, ptl_handle_md_t *mdh)
321 lib_nal_t *nal = apinal->nal_data;
326 LIB_LOCK(nal, flags);
328 md = ptl_handle2md(mdh, nal);
330 LIB_UNLOCK(nal, flags);
331 return PTL_MD_INVALID;
334 /* If the MD is busy, lib_md_unlink just marks it for deletion, and
335 * when the NAL is done, the completion event flags that the MD was
336 * unlinked. Otherwise, we enqueue an event now... */
338 if (md->eq != NULL &&
340 memset(&ev, 0, sizeof(ev));
342 ev.type = PTL_EVENT_UNLINK;
343 ev.ni_fail_type = PTL_OK;
345 lib_md_deconstruct(nal, md, &ev.md);
346 ptl_md2handle(&ev.md_handle, nal, md);
348 lib_enq_event_locked(nal, NULL, md->eq, &ev);
351 lib_md_unlink(nal, md);
353 LIB_UNLOCK(nal, flags);
358 lib_api_md_update (nal_t *apinal,
359 ptl_handle_md_t *mdh,
360 ptl_md_t *oldumd, ptl_md_t *newumd,
361 ptl_handle_eq_t *testqh)
363 lib_nal_t *nal = apinal->nal_data;
365 lib_eq_t *test_eq = NULL;
369 LIB_LOCK(nal, flags);
371 md = ptl_handle2md(mdh, nal);
378 lib_md_deconstruct(nal, md, oldumd);
380 if (newumd == NULL) {
385 /* XXX fttb, the new MD must be the same "shape" wrt fragmentation,
386 * since we simply overwrite the old lib-md */
387 if ((((newumd->options ^ md->options) &
388 (PTL_MD_IOVEC | PTL_MD_KIOV)) != 0) ||
389 ((newumd->options & (PTL_MD_IOVEC | PTL_MD_KIOV)) != 0 &&
390 newumd->length != md->md_niov)) {
391 rc = PTL_IOV_INVALID;
395 if (!PtlHandleIsEqual (*testqh, PTL_EQ_NONE)) {
396 test_eq = ptl_handle2eq(testqh, nal);
397 if (test_eq == NULL) {
403 if (md->pending != 0) {
404 rc = PTL_MD_NO_UPDATE;
408 if (test_eq == NULL ||
409 test_eq->eq_deq_seq == test_eq->eq_enq_seq) {
410 lib_me_t *me = md->me;
411 int unlink = (md->md_flags & PTL_MD_FLAG_AUTO_UNLINK) ?
412 PTL_UNLINK : PTL_RETAIN;
414 // #warning this does not track eq refcounts properly
415 rc = lib_md_build(nal, md, newumd, unlink);
419 rc = PTL_MD_NO_UPDATE;
423 LIB_UNLOCK(nal, flags);