Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 348269
b: refs/heads/master
c: 4a674f3
h: refs/heads/master
i:
  348267: 731315e
v: v3
  • Loading branch information
Stanislav Kinsbursky authored and Linus Torvalds committed Jan 5, 2013
1 parent df5248c commit 05800bc
Show file tree
Hide file tree
Showing 5 changed files with 103 additions and 3 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: f9dd87f4738c7555aca2cdf8cb2b2326cafb0cad
refs/heads/master: 4a674f34ba04a002244edaf891b5da7fc1473ae8
1 change: 1 addition & 0 deletions trunk/include/uapi/linux/msg.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
/* msgrcv options */
#define MSG_NOERROR 010000 /* no error if message is too big */
#define MSG_EXCEPT 020000 /* recv any msg except of specified type.*/
#define MSG_COPY 040000 /* copy (not remove) all queue messages */

/* Obsolete, used only for backwards compatibility and libc5 compiles */
struct msqid_ds {
Expand Down
64 changes: 62 additions & 2 deletions trunk/ipc/msg.c
Original file line number Diff line number Diff line change
Expand Up @@ -769,6 +769,45 @@ static long do_msg_fill(void __user *dest, struct msg_msg *msg, size_t bufsz)
return msgsz;
}

#ifdef CONFIG_CHECKPOINT_RESTORE
static inline struct msg_msg *fill_copy(unsigned long copy_nr,
unsigned long msg_nr,
struct msg_msg *msg,
struct msg_msg *copy)
{
if (copy_nr == msg_nr)
return copy_msg(msg, copy);
return NULL;
}

static inline struct msg_msg *prepare_copy(void __user *buf, size_t bufsz,
int msgflg, long *msgtyp,
unsigned long *copy_number)
{
struct msg_msg *copy;

*copy_number = *msgtyp;
*msgtyp = 0;
/*
* Create dummy message to copy real message to.
*/
copy = load_msg(buf, bufsz);
if (!IS_ERR(copy))
copy->m_ts = bufsz;
return copy;
}

static inline void free_copy(int msgflg, struct msg_msg *copy)
{
if (msgflg & MSG_COPY)
free_msg(copy);
}
#else
#define free_copy(msgflg, copy) do {} while (0)
#define prepare_copy(buf, sz, msgflg, msgtyp, copy_nr) ERR_PTR(-ENOSYS)
#define fill_copy(copy_nr, msg_nr, msg, copy) NULL
#endif

long do_msgrcv(int msqid, void __user *buf, size_t bufsz, long msgtyp,
int msgflg,
long (*msg_handler)(void __user *, struct msg_msg *, size_t))
Expand All @@ -777,19 +816,29 @@ long do_msgrcv(int msqid, void __user *buf, size_t bufsz, long msgtyp,
struct msg_msg *msg;
int mode;
struct ipc_namespace *ns;
struct msg_msg *copy;
unsigned long __maybe_unused copy_number;

if (msqid < 0 || (long) bufsz < 0)
return -EINVAL;
if (msgflg & MSG_COPY) {
copy = prepare_copy(buf, bufsz, msgflg, &msgtyp, &copy_number);
if (IS_ERR(copy))
return PTR_ERR(copy);
}
mode = convert_mode(&msgtyp, msgflg);
ns = current->nsproxy->ipc_ns;

msq = msg_lock_check(ns, msqid);
if (IS_ERR(msq))
if (IS_ERR(msq)) {
free_copy(msgflg, copy);
return PTR_ERR(msq);
}

for (;;) {
struct msg_receiver msr_d;
struct list_head *tmp;
long msg_counter = 0;

msg = ERR_PTR(-EACCES);
if (ipcperms(ns, &msq->q_perm, S_IRUGO))
Expand All @@ -809,8 +858,15 @@ long do_msgrcv(int msqid, void __user *buf, size_t bufsz, long msgtyp,
if (mode == SEARCH_LESSEQUAL &&
walk_msg->m_type != 1) {
msgtyp = walk_msg->m_type - 1;
} else if (msgflg & MSG_COPY) {
msg = fill_copy(copy_number,
msg_counter,
walk_msg, copy);
if (msg)
break;
} else
break;
msg_counter++;
}
tmp = tmp->next;
}
Expand All @@ -823,6 +879,8 @@ long do_msgrcv(int msqid, void __user *buf, size_t bufsz, long msgtyp,
msg = ERR_PTR(-E2BIG);
goto out_unlock;
}
if (msgflg & MSG_COPY)
goto out_unlock;
list_del(&msg->m_list);
msq->q_qnum--;
msq->q_rtime = get_seconds();
Expand Down Expand Up @@ -906,8 +964,10 @@ long do_msgrcv(int msqid, void __user *buf, size_t bufsz, long msgtyp,
break;
}
}
if (IS_ERR(msg))
if (IS_ERR(msg)) {
free_copy(msgflg, copy);
return PTR_ERR(msg);
}

bufsz = msg_handler(buf, msg, bufsz);
free_msg(msg);
Expand Down
38 changes: 38 additions & 0 deletions trunk/ipc/msgutil.c
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,45 @@ struct msg_msg *load_msg(const void __user *src, int len)
free_msg(msg);
return ERR_PTR(err);
}
#ifdef CONFIG_CHECKPOINT_RESTORE
struct msg_msg *copy_msg(struct msg_msg *src, struct msg_msg *dst)
{
struct msg_msgseg *dst_pseg, *src_pseg;
int len = src->m_ts;
int alen;

BUG_ON(dst == NULL);
if (src->m_ts > dst->m_ts)
return ERR_PTR(-EINVAL);

alen = len;
if (alen > DATALEN_MSG)
alen = DATALEN_MSG;

dst->next = NULL;
dst->security = NULL;

memcpy(dst + 1, src + 1, alen);

len -= alen;
dst_pseg = dst->next;
src_pseg = src->next;
while (len > 0) {
alen = len;
if (alen > DATALEN_SEG)
alen = DATALEN_SEG;
memcpy(dst_pseg + 1, src_pseg + 1, alen);
dst_pseg = dst_pseg->next;
len -= alen;
src_pseg = src_pseg->next;
}

dst->m_type = src->m_type;
dst->m_ts = src->m_ts;

return dst;
}
#endif
int store_msg(void __user *dest, struct msg_msg *msg, int len)
{
int alen;
Expand Down
1 change: 1 addition & 0 deletions trunk/ipc/util.h
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,7 @@ int ipc_parse_version (int *cmd);

extern void free_msg(struct msg_msg *msg);
extern struct msg_msg *load_msg(const void __user *src, int len);
extern struct msg_msg *copy_msg(struct msg_msg *src, struct msg_msg *dst);
extern int store_msg(void __user *dest, struct msg_msg *msg, int len);

extern void recompute_msgmni(struct ipc_namespace *);
Expand Down

0 comments on commit 05800bc

Please sign in to comment.