3 * Copyright © 2013 - 2013 UNISYS CORPORATION
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or (at
9 * your option) any later version.
11 * This program is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
14 * NON INFRINGEMENT. See the GNU General Public License for more
18 /* Code here-in is the "glue" that connects controlvm messages with the
19 * sparfilexfer driver, which is used to transfer file contents as payload
20 * across the controlvm channel.
24 #include "controlvm.h"
25 #include "visorchipset.h"
28 #ifdef ENABLE_SPARFILEXFER /* sparfilexfer kernel module enabled in build */
29 #include "sparfilexfer.h"
31 /* Driver-global memory */
32 static LIST_HEAD(Request_list
); /* list of struct any_request *, via
35 /* lock for above pool for allocation of any_request structs, and pool
36 * name; note that kmem_cache_create requires that we keep the storage
37 * for the pool name for the life of the pool
39 static DEFINE_SPINLOCK(Request_list_lock
);
41 static struct kmem_cache
*Request_memory_pool
;
42 static const char Request_memory_pool_name
[] = "filexfer_request_pool";
43 size_t Caller_req_context_bytes
= 0; /* passed to filexfer_constructor() */
45 /* This structure defines a single controlvm GETFILE conversation, which
46 * consists of a single controlvm request message and 1 or more controlvm
49 struct getfile_request
{
50 CONTROLVM_MESSAGE_HEADER controlvm_header
;
51 atomic_t buffers_in_use
;
52 GET_CONTIGUOUS_CONTROLVM_PAYLOAD_FUNC get_contiguous_controlvm_payload
;
53 CONTROLVM_RESPOND_WITH_PAYLOAD_FUNC controlvm_respond_with_payload
;
56 /* This structure defines a single controlvm PUTFILE conversation, which
57 * consists of a single controlvm request with a filename, and additional
58 * controlvm messages with file data.
60 struct putfile_request
{
61 GET_CONTROLVM_FILEDATA_FUNC get_controlvm_filedata
;
62 CONTROLVM_RESPOND_FUNC controlvm_end_putFile
;
65 /* This structure defines a single file transfer operation, which can either
66 * be a GETFILE or PUTFILE.
69 struct list_head req_list
;
70 ulong2 file_request_number
;
71 ulong2 data_sequence_number
;
72 TRANSMITFILE_DUMP_FUNC dump_func
;
75 struct getfile_request get
;
76 struct putfile_request put
;
78 /* Size of caller_context_data will be
79 * <Caller_req_context_bytes> bytes. I aligned this because I
80 * am paranoid about what happens when an arbitrary data
81 * structure with unknown alignment requirements gets copied
82 * here. I want caller_context_data to be aligned to the
83 * coarsest possible alignment boundary that could be required
84 * for any user data structure.
86 u8 caller_context_data
[1] __aligned(sizeof(ulong2
);
90 * Links the any_request into the global list of allocated requests
94 unit_tracking_create(struct list_head
*dev_list_link
)
97 spin_lock_irqsave(&Request_list_lock
, flags
);
98 list_add(dev_list_link
, &Request_list
);
99 spin_unlock_irqrestore(&Request_list_lock
, flags
);
102 /* Unlinks a any_request from the global list (<Request_list>).
105 unit_tracking_destroy(struct list_head
*dev_list_link
)
108 spin_lock_irqsave(&Request_list_lock
, flags
);
109 list_del(dev_list_link
);
110 spin_unlock_irqrestore(&Request_list_lock
, flags
);
113 /* Allocate memory for and return a new any_request struct, and
114 * link it to the global list of outstanding requests.
116 static struct any_request
*
117 alloc_request(char *fn
, int ln
)
119 struct any_request
*req
= (struct any_request
*)
120 (visorchipset_cache_alloc(Request_memory_pool
,
125 memset(req
, 0, sizeof(struct any_request
) + Caller_req_context_bytes
);
126 unit_tracking_create(&req
->req_list
);
130 /* Book-end for alloc_request().
133 free_request(struct any_request
*req
, char *fn
, int ln
)
135 unit_tracking_destroy(&req
->req_list
);
136 visorchipset_cache_free(Request_memory_pool
, req
, fn
, ln
);
139 /* Constructor for filexfer.o.
142 filexfer_constructor(size_t req_context_bytes
)
146 Caller_req_context_bytes
= req_context_bytes
;
147 Request_memory_pool
=
148 kmem_cache_create(Request_memory_pool_name
,
149 sizeof(struct any_request
) +
150 Caller_req_context_bytes
,
151 0, SLAB_HWCACHE_ALIGN
, NULL
);
152 if (!Request_memory_pool
) {
153 LOGERR("failed to alloc Request_memory_pool");
160 if (Request_memory_pool
) {
161 kmem_cache_destroy(Request_memory_pool
);
162 Request_memory_pool
= NULL
;
168 /* Destructor for filexfer.o.
171 filexfer_destructor(void)
173 if (Request_memory_pool
) {
174 kmem_cache_destroy(Request_memory_pool
);
175 Request_memory_pool
= NULL
;
179 /* This function will obtain an available chunk from the controlvm payload area,
180 * store the size in bytes of the chunk in <actual_size>, and return a pointer
181 * to the chunk. The function is passed to the sparfilexfer driver, which calls
182 * it whenever payload space is required to copy file data into.
185 get_empty_bucket_for_getfile_data(void *context
,
186 ulong min_size
, ulong max_size
,
190 struct any_request
*req
= (struct any_request
*) context
;
193 LOGERR("%s - unexpected call", __func__
);
196 bucket
= (*req
->get
.get_contiguous_controlvm_payload
)
197 (min_size
, max_size
, actual_size
);
198 if (bucket
!= NULL
) {
199 atomic_inc(&req
->get
.buffers_in_use
);
200 DBGINF("%s - sent %lu-byte buffer", __func__
, *actual_size
);
205 /* This function will send a controlvm response with data in the payload
206 * (whose space was obtained with get_empty_bucket_for_getfile_data). The
207 * function is passed to the sparfilexfer driver, which calls it whenever it
208 * wants to send file data back across the controlvm channel.
211 send_full_getfile_data_bucket(void *context
, void *bucket
,
212 ulong bucket_actual_size
, ulong bucket_used_size
)
214 struct any_request
*req
= (struct any_request
*) context
;
217 LOGERR("%s - unexpected call", __func__
);
220 DBGINF("sending buffer for %lu/%lu",
221 bucket_used_size
, bucket_actual_size
);
222 if (!(*req
->get
.controlvm_respond_with_payload
)
223 (&req
->get
.controlvm_header
,
224 req
->file_request_number
,
225 req
->data_sequence_number
++,
226 0, bucket
, bucket_actual_size
, bucket_used_size
, TRUE
))
227 atomic_dec(&req
->get
.buffers_in_use
);
231 /* This function will send a controlvm response indicating the end of a
232 * GETFILE transfer. The function is passed to the sparfilexfer driver.
235 send_end_of_getfile_data(void *context
, int status
)
237 struct any_request
*req
= (struct any_request
*) context
;
239 LOGERR("%s - unexpected call", __func__
);
242 LOGINF("status=%d", status
);
243 (*req
->get
.controlvm_respond_with_payload
)
244 (&req
->get
.controlvm_header
,
245 req
->file_request_number
,
246 req
->data_sequence_number
++, status
, NULL
, 0, 0, FALSE
);
247 free_request(req
, __FILE__
, __LINE__
);
248 module_put(THIS_MODULE
);
251 /* This function supplies data for a PUTFILE transfer.
252 * The function is passed to the sparfilexfer driver.
255 get_putfile_data(void *context
, void *pbuf
, size_t bufsize
,
256 BOOL buf_is_userspace
, size_t *bytes_transferred
)
258 struct any_request
*req
= (struct any_request
*) context
;
260 LOGERR("%s - unexpected call", __func__
);
263 return (*req
->put
.get_controlvm_filedata
) (&req
->caller_context_data
[0],
269 /* This function is called to indicate the end of a PUTFILE transfer.
270 * The function is passed to the sparfilexfer driver.
273 end_putfile(void *context
, int status
)
275 struct any_request
*req
= (struct any_request
*) context
;
277 LOGERR("%s - unexpected call", __func__
);
280 (*req
->put
.controlvm_end_putFile
) (&req
->caller_context_data
[0],
282 free_request(req
, __FILE__
, __LINE__
);
283 module_put(THIS_MODULE
);
286 /* Refer to filexfer.h for description. */
288 filexfer_getFile(CONTROLVM_MESSAGE_HEADER
*msgHdr
,
289 ulong2 file_request_number
,
293 GET_CONTIGUOUS_CONTROLVM_PAYLOAD_FUNC
294 get_contiguous_controlvm_payload
,
295 CONTROLVM_RESPOND_WITH_PAYLOAD_FUNC
296 controlvm_respond_with_payload
,
297 TRANSMITFILE_DUMP_FUNC dump_func
)
299 BOOL use_count_up
= FALSE
;
301 struct any_request
*req
= alloc_request(__FILE__
, __LINE__
);
304 LOGERR("allocation of any_request failed");
307 /* We need to increment this module's use count because we're handing
308 * off pointers to functions within this module to be used by
311 __module_get(THIS_MODULE
);
314 req
->file_request_number
= file_request_number
;
315 req
->data_sequence_number
= 0;
316 req
->dump_func
= dump_func
;
317 req
->get
.controlvm_header
= *msgHdr
;
318 atomic_set(&req
->get
.buffers_in_use
, 0);
319 req
->get
.get_contiguous_controlvm_payload
=
320 get_contiguous_controlvm_payload
;
321 req
->get
.controlvm_respond_with_payload
=
322 controlvm_respond_with_payload
;
323 if (sparfilexfer_local2remote(req
, /* context, passed to
329 get_empty_bucket_for_getfile_data
,
330 send_full_getfile_data_bucket
,
331 send_end_of_getfile_data
) < 0) {
332 LOGERR("sparfilexfer_local2remote failed");
339 module_put(THIS_MODULE
);
340 use_count_up
= FALSE
;
343 free_request(req
, __FILE__
, __LINE__
);
349 /* success; send callbacks will be called for responses */
353 /* Refer to filexfer.h for description. */
355 filexfer_putFile(CONTROLVM_MESSAGE_HEADER
*msgHdr
,
356 ulong2 file_request_number
,
360 TRANSMITFILE_INIT_CONTEXT_FUNC init_context
,
361 GET_CONTROLVM_FILEDATA_FUNC get_controlvm_filedata
,
362 CONTROLVM_RESPOND_FUNC controlvm_end_putFile
,
363 TRANSMITFILE_DUMP_FUNC dump_func
)
365 BOOL use_count_up
= FALSE
;
367 struct any_request
*req
= alloc_request(__FILE__
, __LINE__
);
368 void *caller_ctx
= NULL
;
371 LOGERR("allocation of any_request failed");
374 caller_ctx
= (void *) (&(req
->caller_context_data
[0]));
375 /* We need to increment this module's use count because we're handing
376 * off pointers to functions within this module to be used by
379 __module_get(THIS_MODULE
);
382 req
->file_request_number
= file_request_number
;
383 req
->data_sequence_number
= 0;
384 req
->dump_func
= dump_func
;
385 req
->put
.get_controlvm_filedata
= get_controlvm_filedata
;
386 req
->put
.controlvm_end_putFile
= controlvm_end_putFile
;
387 (*init_context
) (caller_ctx
, msgHdr
, file_request_number
);
388 if (sparfilexfer_remote2local(req
, /* context, passed to
394 get_putfile_data
, end_putfile
) < 0) {
395 LOGERR("sparfilexfer_remote2local failed");
402 module_put(THIS_MODULE
);
403 use_count_up
= FALSE
;
406 free_request(req
, __FILE__
, __LINE__
);
412 /* success; callbacks will be called for responses */
417 dump_get_request(struct seq_file
*f
, struct getfile_request
*getreq
)
419 seq_printf(f
, " buffers_in_use=%d\n",
420 atomic_read(&getreq
->buffers_in_use
));
424 dump_put_request(struct seq_file
*f
, struct putfile_request
*putreq
)
429 dump_request(struct seq_file
*f
, struct any_request
*req
)
431 seq_printf(f
, "* %s id=%llu seq=%llu\n",
432 ((req
->is_get
) ? "Get" : "Put"),
433 req
->file_request_number
, req
->data_sequence_number
);
435 dump_get_request(f
, &req
->get
);
437 dump_put_request(f
, &req
->put
);
439 (*req
->dump_func
) (f
, &(req
->caller_context_data
[0]), " ");
443 filexfer_dump(struct seq_file
*f
)
446 struct list_head
*entry
;
448 seq_puts(f
, "Outstanding TRANSMIT_FILE requests:\n");
449 spin_lock_irqsave(&Request_list_lock
, flags
);
450 list_for_each(entry
, &Request_list
) {
451 struct any_request
*req
;
452 req
= list_entry(entry
, struct any_request
, req_list
);
453 dump_request(f
, req
);
455 spin_unlock_irqrestore(&Request_list_lock
, flags
);
458 #else /* ifdef ENABLE_SPARFILEXFER */
460 filexfer_constructor(size_t req_context_bytes
)
462 return 0; /* success */
466 filexfer_destructor(void)
471 filexfer_getFile(CONTROLVM_MESSAGE_HEADER
*msgHdr
,
472 u64 file_request_number
,
476 GET_CONTIGUOUS_CONTROLVM_PAYLOAD_FUNC
477 get_contiguous_controlvm_payload
,
478 CONTROLVM_RESPOND_WITH_PAYLOAD_FUNC
479 controlvm_respond_with_payload
,
480 TRANSMITFILE_DUMP_FUNC dump_func
)
482 /* since no sparfilexfer module exists to call, we just fail */
487 filexfer_putFile(CONTROLVM_MESSAGE_HEADER
*msgHdr
,
488 u64 file_request_number
,
492 TRANSMITFILE_INIT_CONTEXT_FUNC init_context
,
493 GET_CONTROLVM_FILEDATA_FUNC get_controlvm_filedata
,
494 CONTROLVM_RESPOND_FUNC controlvm_end_putFile
,
495 TRANSMITFILE_DUMP_FUNC dump_func
)
497 /* since no sparfilexfer module exists to call, we just fail */
502 filexfer_dump(struct seq_file
*f
)
506 #endif /* ifdef ENABLE_SPARFILEXFER */