Created
September 19, 2016 15:07
-
-
Save dvdhrm/89826757073b28ae2533e7f41eae1b45 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
static int bus1_peer_transfer(struct bus1_peer *src, | |
struct bus1_peer *dst, | |
struct bus1_cmd_handle_transfer *param) | |
{ | |
struct bus1_handle *src_h, *dst_h; | |
int r = 0; | |
mutex_lock(&src->local.lock); | |
src_h = bus1_handle_ref_by_id(src, param.src_handle); | |
if (src_h) { | |
/* | |
* We know @src_h has a valid user-ref which is protected by | |
* local.lock. Hence, we can acquire the remote handle and know | |
* @src_h stays valid. If the remote-acquisition fails, we can | |
* safely bail out. If it succeeds, we must settle on the | |
* target node and make sure it is still live (returning | |
* EHOSTUNREACH without settling first would break causal | |
* order). If after settle the node is dead, we can safely bail | |
* out without triggering any release (dead nodes cannot | |
* trigger anything). But if it is life, we now have acquired a | |
* valid inflight reference and nothing prevents us from | |
* disclosing it. | |
*/ | |
dst_h = bus1_handle_attach(src_h, dst); | |
if (IS_ERR(dst_h)) { | |
r = PTR_ERR(dst_h); | |
} else if (!bus1_handle_settle(src_h)) { | |
dst_h = bus1_handle_release(dst_h, NULL); | |
r = -EHOSTUNREACH; | |
} | |
} else if (param.src_handle & BUS1_HANDLE_FLAG_REMOTE) { | |
/* | |
* Cannot find any handle with the given ID, but the ID was | |
* marked as remote ID. This is a caller error, so tell them | |
* about it. | |
*/ | |
r = -ENXIO; | |
} else { | |
/* | |
* No handle with the given ID exists, but it is a local ID. | |
* Hence, the caller wants us to create a new node with it. We | |
* allocate the node and attach a remote handle. If the attach | |
* fails, we can easily unref the unused node. If it succeeds, | |
* we have it properly pinned and nothing prevents us from | |
* disclosing it. We first disclose the source, though. This | |
* makes sure the newly created node is actually valid and | |
* usable by the peer. | |
* Note that there is no need to settle. The new node is | |
* completely unlinked, so the settle can be skipped. | |
*/ | |
src_h = bus1_node_new(param.src_handle); | |
if (IS_ERR(src_h)) { | |
r = PTR_ERR(src_h); | |
src_h = NULL; | |
} else { | |
dst_h = bus1_handle_attach(src_h, dst); | |
if (IS_ERR(dst_h)) | |
r = PTR_ERR(dst_h); | |
else | |
bus1_handle_disclose(src_h); | |
} | |
} | |
mutex_unlock(&src->local.lock); | |
bus1_handle_unref(src_h); | |
if (r < 0) | |
return r; | |
mutex_lock(&dst->local.lock); | |
bus1_handle_disclose(dst_h); | |
/* remote-user on @dst_h, so this cannot trigger release */ | |
bus1_handle_release(dst_h, NULL); | |
mutex_unlock(&dst->local.lock); | |
return 0; | |
error: | |
mutex_unlock(&src->local.lock); | |
return r; | |
} | |
static int bus1_peer_ioctl_handle_transfer(struct bus1_peer *src, | |
unsigned long arg) | |
{ | |
struct bus1_cmd_handle_transfer __user *uparam = (void __user *) arg; | |
struct bus1_cmd_handle_transfer param; | |
struct bus1_peer *dst = NULL; | |
struct fd dst_f; | |
int r; | |
BUILD_BUG_ON(_IOC_SIZE(BUS1_CMD_HANDLE_TRANSFER) != sizeof(param)); | |
if (copy_from_user(¶m, (void __user *)arg, sizeof(param))) | |
return -EFAULT; | |
if (unlikely(param.flags)) | |
return -EINVAL; | |
if (param.dst_fd != -1) { | |
dst_f = fdget(param.dst_fd); | |
if (!dst_f.file) | |
return -EBADF; | |
if (dst_f.file->f_op != &bus1_fops) { | |
fdput(dst_f); | |
return -EOPNOTSUPP; | |
} | |
dst = bus1_peer_acquire(dst_f.file->private_data); | |
fdput(dst_f); | |
if (!dst) | |
return -ESHUTDOWN; | |
} | |
r = bus1_peer_transfer(src, dst ?: src, ¶m); | |
bus1_peer_release(dst); | |
if (r < 0) | |
return r; | |
return copy_to_user(uparam, ¶m, sizeof(param)) ? -EFAULT : 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment