static int metadata_update_finish(struct mddev *mddev) { struct md_cluster_info *cinfo = mddev->cluster_info; struct cluster_msg cmsg; struct md_rdev *rdev; int ret = 0; int raid_slot = -1; memset(&cmsg, 0, sizeof(cmsg)); cmsg.type = cpu_to_le32(METADATA_UPDATED); /* Pick up a good active device number to send. */ rdev_for_each(rdev, mddev) if (rdev->raid_disk > -1 && !test_bit(Faulty, &rdev->flags)) { raid_slot = rdev->desc_nr; break; } if (raid_slot >= 0) { cmsg.raid_slot = cpu_to_le32(raid_slot); ret = __sendmsg(cinfo, &cmsg); } else pr_warn("md-cluster: No good device id found to send\n"); unlock_comm(cinfo); return ret; }
static int add_new_disk_start(struct mddev *mddev, struct md_rdev *rdev) { struct md_cluster_info *cinfo = mddev->cluster_info; struct cluster_msg cmsg; int ret = 0; struct mdp_superblock_1 *sb = page_address(rdev->sb_page); char *uuid = sb->device_uuid; memset(&cmsg, 0, sizeof(cmsg)); cmsg.type = cpu_to_le32(NEWDISK); memcpy(cmsg.uuid, uuid, 16); cmsg.raid_slot = rdev->desc_nr; lock_comm(cinfo); ret = __sendmsg(cinfo, &cmsg); if (ret) return ret; cinfo->no_new_dev_lockres->flags |= DLM_LKF_NOQUEUE; ret = dlm_lock_sync(cinfo->no_new_dev_lockres, DLM_LOCK_EX); cinfo->no_new_dev_lockres->flags &= ~DLM_LKF_NOQUEUE; /* Some node does not "see" the device */ if (ret == -EAGAIN) ret = -ENOENT; else dlm_lock_sync(cinfo->no_new_dev_lockres, DLM_LOCK_CR); return ret; }
ssize_t sendmsg(int sock, const struct msghdr *msg, int flags) { int r; int uds_sotype; r = __sendmsg(sock, msg, flags); if (r != -1 || (errno != ENOTSOCK && errno != ENOSYS)) return r; if (msg == NULL) { errno= EFAULT; return -1; } /* For old socket driver implementations, this flag is the default. */ flags &= ~MSG_NOSIGNAL; r= ioctl(sock, NWIOGUDSSOTYPE, &uds_sotype); if (r != -1 || errno != ENOTTY) { if (r == -1) { return r; } if (uds_sotype == SOCK_DGRAM) { return _uds_sendmsg_dgram(sock, msg, flags); } else { return _uds_sendmsg_conn(sock, msg, flags); } } errno = ENOTSOCK; return -1; }
static int remove_disk(struct mddev *mddev, struct md_rdev *rdev) { struct cluster_msg cmsg; struct md_cluster_info *cinfo = mddev->cluster_info; cmsg.type = REMOVE; cmsg.raid_slot = rdev->desc_nr; return __sendmsg(cinfo, &cmsg); }
static int remove_disk(struct mddev *mddev, struct md_rdev *rdev) { struct cluster_msg cmsg = {0}; struct md_cluster_info *cinfo = mddev->cluster_info; cmsg.type = cpu_to_le32(REMOVE); cmsg.raid_slot = cpu_to_le32(rdev->desc_nr); return __sendmsg(cinfo, &cmsg); }
static int sendmsg(struct md_cluster_info *cinfo, struct cluster_msg *cmsg) { int ret; lock_comm(cinfo); ret = __sendmsg(cinfo, cmsg); unlock_comm(cinfo); return ret; }
static int add_new_disk_finish(struct mddev *mddev) { struct cluster_msg cmsg; struct md_cluster_info *cinfo = mddev->cluster_info; int ret; /* Write sb and inform others */ md_update_sb(mddev, 1); cmsg.type = METADATA_UPDATED; ret = __sendmsg(cinfo, &cmsg); unlock_comm(cinfo); return ret; }
static int metadata_update_finish(struct mddev *mddev) { struct md_cluster_info *cinfo = mddev->cluster_info; struct cluster_msg cmsg; int ret; memset(&cmsg, 0, sizeof(cmsg)); cmsg.type = cpu_to_le32(METADATA_UPDATED); ret = __sendmsg(cinfo, &cmsg); unlock_comm(cinfo); return ret; }
static int __msgwrite (int sock, void *data, size_t cnt) { #ifndef SCM_CREDENTIALS /* We cannot implement this reliably. */ __set_errno (ENOSYS); return -1; #else struct iovec iov; struct msghdr msg; struct cmsghdr *cmsg = &cm.cmsg; struct ucred cred; int len; /* XXX I'm not sure, if gete?id() is always correct, or if we should use get?id(). But since keyserv needs geteuid(), we have no other chance. It would be much better, if the kernel could pass both to the server. */ cred.pid = __getpid (); cred.uid = __geteuid (); cred.gid = __getegid (); memcpy (CMSG_DATA(cmsg), &cred, sizeof (struct ucred)); cmsg->cmsg_level = SOL_SOCKET; cmsg->cmsg_type = SCM_CREDENTIALS; cmsg->cmsg_len = sizeof(*cmsg) + sizeof(struct ucred); iov.iov_base = data; iov.iov_len = cnt; msg.msg_iov = &iov; msg.msg_iovlen = 1; msg.msg_name = NULL; msg.msg_namelen = 0; msg.msg_control = cmsg; msg.msg_controllen = CMSG_ALIGN(cmsg->cmsg_len); msg.msg_flags = 0; restart: len = __sendmsg (sock, &msg, 0); if (len >= 0) return len; if (errno == EINTR) goto restart; return -1; #endif }
/* add_new_disk() - initiates a disk add * However, if this fails before writing md_update_sb(), * add_new_disk_cancel() must be called to release token lock */ static int add_new_disk(struct mddev *mddev, struct md_rdev *rdev) { struct md_cluster_info *cinfo = mddev->cluster_info; struct cluster_msg cmsg; int ret = 0; struct mdp_superblock_1 *sb = page_address(rdev->sb_page); char *uuid = sb->device_uuid; memset(&cmsg, 0, sizeof(cmsg)); cmsg.type = cpu_to_le32(NEWDISK); memcpy(cmsg.uuid, uuid, 16); cmsg.raid_slot = cpu_to_le32(rdev->desc_nr); lock_comm(cinfo); ret = __sendmsg(cinfo, &cmsg); if (ret) return ret; cinfo->no_new_dev_lockres->flags |= DLM_LKF_NOQUEUE; ret = dlm_lock_sync(cinfo->no_new_dev_lockres, DLM_LOCK_EX); cinfo->no_new_dev_lockres->flags &= ~DLM_LKF_NOQUEUE; /* Some node does not "see" the device */ if (ret == -EAGAIN) ret = -ENOENT; if (ret) unlock_comm(cinfo); else { dlm_lock_sync(cinfo->no_new_dev_lockres, DLM_LOCK_CR); /* Since MD_CHANGE_DEVS will be set in add_bound_rdev which * will run soon after add_new_disk, the below path will be * invoked: * md_wakeup_thread(mddev->thread) * -> conf->thread (raid1d) * -> md_check_recovery -> md_update_sb * -> metadata_update_start/finish * MD_CLUSTER_SEND_LOCKED_ALREADY will be cleared eventually. * * For other failure cases, metadata_update_cancel and * add_new_disk_cancel also clear below bit as well. * */ set_bit(MD_CLUSTER_SEND_LOCKED_ALREADY, &cinfo->state); wake_up(&cinfo->wait); } return ret; }
static bool_t rendezvous_request (SVCXPRT *xprt, struct rpc_msg *errmsg) { int sock; struct unix_rendezvous *r; struct sockaddr_un addr; struct sockaddr_in in_addr; socklen_t len; r = (struct unix_rendezvous *) xprt->xp_p1; again: len = sizeof (struct sockaddr_un); if ((sock = accept (xprt->xp_sock, (struct sockaddr *) &addr, &len)) < 0) { if (errno == EINTR) goto again; if (errno == EMFILE) { struct timespec ts = { .tv_sec = 0, .tv_nsec = 50000000 }; __nanosleep(&ts , NULL); } return FALSE; } /* * make a new transporter (re-uses xprt) */ memset (&in_addr, '\0', sizeof (in_addr)); in_addr.sin_family = AF_UNIX; xprt = makefd_xprt (sock, r->sendsize, r->recvsize); memcpy (&xprt->xp_raddr, &in_addr, sizeof (in_addr)); xprt->xp_addrlen = len; return FALSE; /* there is never an rpc msg to be processed */ } static enum xprt_stat rendezvous_stat (SVCXPRT *xprt) { return XPRT_IDLE; } static void svcunix_destroy (SVCXPRT *xprt) { struct unix_conn *cd = (struct unix_conn *) xprt->xp_p1; xprt_unregister (xprt); __close (xprt->xp_sock); if (xprt->xp_port != 0) { /* a rendezvouser socket */ xprt->xp_port = 0; } else { /* an actual connection socket */ XDR_DESTROY (&(cd->xdrs)); } mem_free ((caddr_t) cd, sizeof (struct unix_conn)); mem_free ((caddr_t) xprt, sizeof (SVCXPRT)); } #ifdef SCM_CREDENTIALS struct cmessage { struct cmsghdr cmsg; struct ucred cmcred; /* hack to make sure we have enough memory */ char dummy[(CMSG_ALIGN (sizeof (struct ucred)) - sizeof (struct ucred) + sizeof (long))]; }; /* XXX This is not thread safe, but since the main functions in svc.c and the rpcgen generated *_svc functions for the daemon are also not thread safe and uses static global variables, it doesn't matter. */ static struct cmessage cm; #endif static int __msgread (int sock, void *data, size_t cnt) { struct iovec iov; struct msghdr msg; int len; iov.iov_base = data; iov.iov_len = cnt; msg.msg_iov = &iov; msg.msg_iovlen = 1; msg.msg_name = NULL; msg.msg_namelen = 0; #ifdef SCM_CREDENTIALS msg.msg_control = (caddr_t) &cm; msg.msg_controllen = sizeof (struct cmessage); #endif msg.msg_flags = 0; #ifdef SO_PASSCRED { int on = 1; if (__setsockopt (sock, SOL_SOCKET, SO_PASSCRED, &on, sizeof (on))) return -1; } #endif restart: len = __recvmsg (sock, &msg, 0); if (len >= 0) { if (msg.msg_flags & MSG_CTRUNC || len == 0) return 0; else return len; } if (errno == EINTR) goto restart; return -1; } static int __msgwrite (int sock, void *data, size_t cnt) { #ifndef SCM_CREDENTIALS /* We cannot implement this reliably. */ __set_errno (ENOSYS); return -1; #else struct iovec iov; struct msghdr msg; struct cmsghdr *cmsg = &cm.cmsg; struct ucred cred; int len; /* XXX I'm not sure, if gete?id() is always correct, or if we should use get?id(). But since keyserv needs geteuid(), we have no other chance. It would be much better, if the kernel could pass both to the server. */ cred.pid = __getpid (); cred.uid = __geteuid (); cred.gid = __getegid (); memcpy (CMSG_DATA(cmsg), &cred, sizeof (struct ucred)); cmsg->cmsg_level = SOL_SOCKET; cmsg->cmsg_type = SCM_CREDENTIALS; cmsg->cmsg_len = sizeof(*cmsg) + sizeof(struct ucred); iov.iov_base = data; iov.iov_len = cnt; msg.msg_iov = &iov; msg.msg_iovlen = 1; msg.msg_name = NULL; msg.msg_namelen = 0; msg.msg_control = cmsg; msg.msg_controllen = CMSG_ALIGN(cmsg->cmsg_len); msg.msg_flags = 0; restart: len = __sendmsg (sock, &msg, 0); if (len >= 0) return len; if (errno == EINTR) goto restart; return -1; #endif }