60
60
static struct list_head hgfsRepPending; /* Reply pending queue. */
61
61
static spinlock_t hgfsRepQueueLock; /* Reply pending queue lock. */
63
#define HgfsRequestId(req) ((HgfsRequest *)req)->id
67
* Private function implementations.
64
*----------------------------------------------------------------------
66
* HgfsTransportOpenChannel --
68
* Opens given communication channel with HGFS server.
71
* TRUE on success, FALSE on failure.
76
*----------------------------------------------------------------------
80
HgfsTransportOpenChannel(HgfsTransportChannel *channel)
84
switch (channel->status) {
85
case HGFS_CHANNEL_UNINITIALIZED:
86
case HGFS_CHANNEL_DEAD:
90
case HGFS_CHANNEL_CONNECTED:
94
case HGFS_CHANNEL_NOTCONNECTED:
95
ret = channel->ops.open(channel);
97
channel->status = HGFS_CHANNEL_CONNECTED;
103
ASSERT(0); /* Not reached. */
111
*----------------------------------------------------------------------
113
* HgfsTransportCloseChannel --
115
* Closes currently open communication channel. Has to be called
116
* while holdingChannelLock.
124
*----------------------------------------------------------------------
128
HgfsTransportCloseChannel(HgfsTransportChannel *channel)
130
if (channel->status == HGFS_CHANNEL_CONNECTED ||
131
channel->status == HGFS_CHANNEL_DEAD) {
133
channel->ops.close(channel);
134
channel->status = HGFS_CHANNEL_NOTCONNECTED;
71
140
*----------------------------------------------------------------------
87
156
HgfsTransportSetupNewChannel(void)
89
hgfsChannel = HgfsGetVSocketChannel();
90
if (hgfsChannel != NULL) {
91
if (hgfsChannel->ops.open(hgfsChannel)) {
96
hgfsChannel = HgfsGetTcpChannel();
97
if (hgfsChannel != NULL) {
98
if (hgfsChannel->ops.open(hgfsChannel)) {
103
hgfsChannel = HgfsGetBdChannel();
104
if (hgfsChannel != NULL) {
105
if (hgfsChannel->ops.open(hgfsChannel)) {
116
*----------------------------------------------------------------------
118
* HgfsTransportStopCurrentChannel --
120
* Teardown current channel and stop current receive thread.
128
*----------------------------------------------------------------------
132
HgfsTransportStopCurrentChannel(void)
135
hgfsChannel->ops.exit(hgfsChannel);
142
*----------------------------------------------------------------------
144
* HgfsTransportChannelFailover --
146
* Called when current channel doesn't work. Find a new channel
150
* TRUE on success, otherwise FALSE;
153
* Teardown current opened channel and the receive thread, set up
154
* new channel and new receive thread.
156
*----------------------------------------------------------------------
160
HgfsTransportChannelFailover(void) {
162
HgfsTransportStopCurrentChannel();
163
ret = HgfsTransportSetupNewChannel();
164
LOG(8, ("VMware hgfs: %s result: %s.\n", __func__, ret ? "TRUE" : "FALSE"));
158
HgfsTransportChannel *newChannel;
160
newChannel = HgfsGetVSocketChannel();
161
if (newChannel != NULL) {
162
if (HgfsTransportOpenChannel(newChannel)) {
163
hgfsChannel = newChannel;
168
newChannel = HgfsGetTcpChannel();
169
if (newChannel != NULL) {
170
if (HgfsTransportOpenChannel(newChannel)) {
171
hgfsChannel = newChannel;
176
newChannel = HgfsGetBdChannel();
178
hgfsChannel = newChannel;
179
return HgfsTransportOpenChannel(newChannel);
217
231
spin_lock(&hgfsRepQueueLock);
218
if (!list_empty(&req->list)) {
219
list_del_init(&req->list);
221
spin_unlock(&hgfsRepQueueLock);
226
* Public function implementations.
230
*----------------------------------------------------------------------
232
* HgfsTransportProcessPacket --
234
* Helper function to process received packets, called by the channel
243
*----------------------------------------------------------------------
247
HgfsTransportProcessPacket(char *receivedPacket, //IN: received packet
248
size_t receivedSize) //IN: packet size
250
struct list_head *cur, *next;
256
ASSERT(receivedPacket != NULL && receivedSize > 0);
257
id = HgfsRequestId(receivedPacket);
258
LOG(8, ("VMware hgfs: %s entered.\n", __func__));
259
LOG(6, (KERN_DEBUG "VMware hgfs: %s: req id: %d\n", __func__, id));
232
list_del_init(&req->list);
233
spin_unlock(&hgfsRepQueueLock);
238
*----------------------------------------------------------------------
240
* HgfsTransportFlushPendingRequests --
242
* Complete all submitted requests with an error, called when
243
* we are about to tear down communication channel.
251
*----------------------------------------------------------------------
255
HgfsTransportFlushPendingRequests(void)
259
spin_lock(&hgfsRepQueueLock);
261
list_for_each_entry(req, &hgfsRepPending, list) {
262
if (req->state == HGFS_REQ_STATE_SUBMITTED) {
263
LOG(6, ("VMware hgfs: %s: injecting error reply to req id: %d\n",
265
HgfsFailReq(req, -EIO);
269
spin_unlock(&hgfsRepQueueLock);
273
*----------------------------------------------------------------------
275
* HgfsTransportGetPendingRequest --
277
* Attempts to locate request with specified ID in the queue of
278
* pending (waiting for server's reply) requests.
281
* NULL if request not found; otherwise address of the request
285
* Increments reference count of the request.
287
*----------------------------------------------------------------------
291
HgfsTransportGetPendingRequest(HgfsHandle id) // IN: id of the request
293
HgfsReq *cur, *req = NULL;
295
spin_lock(&hgfsRepQueueLock);
297
list_for_each_entry(cur, &hgfsRepPending, list) {
299
ASSERT(cur->state == HGFS_REQ_STATE_SUBMITTED);
300
req = HgfsRequestGetRef(cur);
305
spin_unlock(&hgfsRepQueueLock);
312
*----------------------------------------------------------------------
314
* HgfsTransportAllocateRequest --
316
* Allocates HGFS request structre using channel-specific allocator.
319
* NULL on failure; otherwisepointer to newly allocated request.
324
*----------------------------------------------------------------------
328
HgfsTransportAllocateRequest(size_t bufferSize) // IN: size of the buffer
261
* Search through hgfsRepPending queue for the matching id and wake up
262
* the associated waiting process. Delete the req from the queue.
332
* We use a temporary variable to make sure we stamp the request with
333
* same channel as we used to make allocation since hgfsChannel can
334
* be changed while we do allocation.
264
spin_lock(&hgfsRepQueueLock);
265
list_for_each_safe(cur, next, &hgfsRepPending) {
267
req = list_entry(cur, HgfsReq, list);
269
ASSERT(req->state == HGFS_REQ_STATE_SUBMITTED);
270
HgfsCompleteReq(req, receivedPacket, receivedSize);
275
spin_unlock(&hgfsRepQueueLock);
278
LOG(4, ("VMware hgfs: %s: No matching id, dropping reply\n",
281
LOG(8, ("VMware hgfs: %s exited.\n", __func__));
286
*----------------------------------------------------------------------
288
* HgfsTransportBeforeExitingRecvThread --
290
* The cleanup work to do before the recv thread exits, including
291
* completing pending requests with error.
299
*----------------------------------------------------------------------
303
HgfsTransportBeforeExitingRecvThread(void)
305
struct list_head *cur, *next;
307
/* Walk through hgfsRepPending queue and reply them with error. */
308
spin_lock(&hgfsRepQueueLock);
309
list_for_each_safe(cur, next, &hgfsRepPending) {
313
/* XXX: Make the request senders be aware of this error. */
315
req = list_entry(cur, HgfsReq, list);
316
LOG(6, ("VMware hgfs: %s: injecting error reply to req id: %d\n",
318
HgfsCompleteReq(req, (char *)&reply, sizeof reply);
320
spin_unlock(&hgfsRepQueueLock);
336
HgfsTransportChannel *currentChannel = hgfsChannel;
338
ASSERT(currentChannel);
340
req = currentChannel->ops.allocate(bufferSize);
342
req->transportId = currentChannel;
341
366
HgfsTransportSendRequest(HgfsReq *req) // IN: Request to send
368
HgfsReq *origReq = req;
345
372
ASSERT(req->state == HGFS_REQ_STATE_UNSENT);
346
373
ASSERT(req->payloadSize <= HGFS_PACKET_MAX);
348
375
compat_mutex_lock(&hgfsChannelLock);
350
/* Try opening the channel. */
351
if (!hgfsChannel && !HgfsTransportSetupNewChannel()) {
352
compat_mutex_unlock(&hgfsChannelLock);
356
ASSERT(hgfsChannel->ops.send);
358
377
HgfsTransportAddPendingRequest(req);
360
while ((ret = hgfsChannel->ops.send(hgfsChannel, req)) != 0) {
361
LOG(4, (KERN_DEBUG "VMware hgfs: %s: send failed. Return %d\n",
381
if (unlikely(hgfsChannel->status != HGFS_CHANNEL_CONNECTED)) {
382
if (hgfsChannel->status == HGFS_CHANNEL_DEAD) {
383
HgfsTransportCloseChannel(hgfsChannel);
384
HgfsTransportFlushPendingRequests();
387
if (!HgfsTransportSetupNewChannel()) {
393
ASSERT(hgfsChannel->ops.send);
395
/* If channel changed since we created request we need to adjust */
396
if (req->transportId != hgfsChannel) {
398
HgfsTransportRemovePendingRequest(req);
400
if (req != origReq) {
401
HgfsRequestPutRef(req);
404
req = HgfsCopyRequest(origReq);
411
HgfsTransportAddPendingRequest(req);
414
ret = hgfsChannel->ops.send(hgfsChannel, req);
415
if (likely(ret == 0))
418
LOG(4, (KERN_DEBUG "VMware hgfs: %s: send failed with error %d\n",
363
421
if (ret == -EINTR) {
364
422
/* Don't retry when we are interrupted by some signal. */
367
if (!hgfsChannel->ops.open(hgfsChannel) && !HgfsTransportChannelFailover()) {
368
/* Can't establish a working channel, just report error. */
426
hgfsChannel->status = HGFS_CHANNEL_DEAD;
374
430
ASSERT(req->state == HGFS_REQ_STATE_COMPLETED ||
375
431
req->state == HGFS_REQ_STATE_SUBMITTED);
418
484
spin_lock_init(&hgfsRepQueueLock);
419
485
compat_mutex_init(&hgfsChannelLock);
487
compat_mutex_lock(&hgfsChannelLock);
489
hgfsChannel = HgfsGetBdChannel();
492
compat_mutex_unlock(&hgfsChannelLock);
497
*----------------------------------------------------------------------
499
* HgfsTransportMarkDead --
501
* Marks current channel as dead so it can be cleaned up and
502
* fails all submitted requests.
510
*----------------------------------------------------------------------
514
HgfsTransportMarkDead(void)
516
LOG(8, ("VMware hgfs: %s entered.\n", __func__));
518
compat_mutex_lock(&hgfsChannelLock);
521
hgfsChannel->status = HGFS_CHANNEL_DEAD;
523
HgfsTransportFlushPendingRequests();
525
compat_mutex_unlock(&hgfsChannelLock);