From: Vyacheslav Cherkashin Date: Tue, 14 Jul 2015 10:12:33 +0000 (+0300) Subject: [FIX] deadlock during __switch_to() instrumentation X-Git-Tag: submit/tizen/20151123.110932~30 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=refs%2Fchanges%2F34%2F43834%2F1;p=kernel%2Fswap-modules.git [FIX] deadlock during __switch_to() instrumentation during __switch_to() handler execution we have 'rq->lock' locked by __schedule(). So we can not call schedule_work() (which also uses 'rq->lock') Change-Id: If8f0b0302d27ef21c80be7433e7ad3b5b0400668 Signed-off-by: Vyacheslav Cherkashin --- diff --git a/buffer/buffer_queue.c b/buffer/buffer_queue.c index 2a7c39e..803e930 100644 --- a/buffer/buffer_queue.c +++ b/buffer/buffer_queue.c @@ -425,19 +425,14 @@ void add_to_read_list(struct swap_subbuffer *subbuffer) sync_unlock(&read_queue.queue_sync); } -/** - * @brief Call add to read list and callback function from driver module. - * - * @param subbuffer Pointer to the subbuffer to add. - * @return swap_buffer_callback result. - */ -int add_to_read_list_with_callback(struct swap_subbuffer *subbuffer) +static int add_to_read_list_with_callback(struct swap_subbuffer *subbuffer, + bool wakeup) { int result = 0; add_to_read_list(subbuffer); /* TODO Handle ret value */ - result = swap_buffer_callback(subbuffer); + result = swap_buffer_callback(subbuffer, wakeup); return result; } @@ -461,7 +456,8 @@ unsigned int get_readable_buf_cnt(void) * beginning of memory for writing should be stored. * @return Found swap_subbuffer. */ -struct swap_subbuffer *get_from_write_list(size_t size, void **ptr_to_write) +struct swap_subbuffer *get_from_write_list(size_t size, void **ptr_to_write, + bool wakeup) { struct swap_subbuffer *result = NULL; @@ -532,7 +528,7 @@ struct swap_subbuffer *get_from_write_list(size_t size, void **ptr_to_write) callback_queue.start_ptr = callback_queue.start_ptr->next_in_queue; - add_to_read_list_with_callback(tmp_buffer); + add_to_read_list_with_callback(tmp_buffer, wakeup); } return result; diff --git a/buffer/buffer_queue.h b/buffer/buffer_queue.h index f89ee99..9b3291e 100644 --- a/buffer/buffer_queue.h +++ b/buffer/buffer_queue.h @@ -32,6 +32,7 @@ #ifndef __BUFFER_QUEUE_H__ #define __BUFFER_QUEUE_H__ +#include #include "buffer_description.h" int buffer_queue_allocation(size_t subbuffer_size, @@ -39,7 +40,8 @@ int buffer_queue_allocation(size_t subbuffer_size, void buffer_queue_free(void); int buffer_queue_reset(void); void buffer_queue_flush(void); -struct swap_subbuffer *get_from_write_list(size_t size, void **ptr_to_write); +struct swap_subbuffer *get_from_write_list(size_t size, void **ptr_to_write, + bool wakeup); struct swap_subbuffer *get_from_read_list(void); void add_to_write_list(struct swap_subbuffer *subbuffer); void add_to_read_list(struct swap_subbuffer *subbuffer); diff --git a/buffer/swap_buffer_module.c b/buffer/swap_buffer_module.c index 1f4a0f8..551f940 100644 --- a/buffer/swap_buffer_module.c +++ b/buffer/swap_buffer_module.c @@ -49,7 +49,7 @@ static unsigned char swap_buffer_status = BUFFER_FREE; /** * @brief Subbuffer callback type. */ -typedef int(*subbuffer_callback_type)(void); +typedef int(*subbuffer_callback_type)(bool wakeup); /* Callback that is called when full subbuffer appears */ static subbuffer_callback_type subbuffer_callback; @@ -188,7 +188,7 @@ EXPORT_SYMBOL_GPL(swap_buffer_uninit); * @param size Size of a data for writing. * @return Size of written data on success, negative error code otherwise. */ -ssize_t swap_buffer_write(void *data, size_t size) +ssize_t swap_buffer_write(void *data, size_t size, bool wakeup) { int result = E_SB_SUCCESS; struct swap_subbuffer *buffer_to_write = NULL; @@ -207,7 +207,7 @@ ssize_t swap_buffer_write(void *data, size_t size) swap_irq_disable(&flags); /* Get next write buffer and occupying semaphore */ - buffer_to_write = get_from_write_list(size, &ptr_to_write); + buffer_to_write = get_from_write_list(size, &ptr_to_write, wakeup); if (!buffer_to_write) { swap_irq_enable(&flags); return -E_SB_NO_WRITABLE_BUFFERS; @@ -329,14 +329,14 @@ EXPORT_SYMBOL_GPL(swap_buffer_flush); * @return -E_SB_NO_CALLBACK if no callback is registered or callbacks ret * value otherwise. */ -int swap_buffer_callback(void *buffer) +int swap_buffer_callback(void *buffer, bool wakeup) { int result; if (!subbuffer_callback) return -E_SB_NO_CALLBACK; - result = subbuffer_callback(); + result = subbuffer_callback(wakeup); if (result < 0) print_err("Callback error! Error code: %d\n", result); diff --git a/buffer/swap_buffer_module.h b/buffer/swap_buffer_module.h index 4a4a8db..95b31fa 100644 --- a/buffer/swap_buffer_module.h +++ b/buffer/swap_buffer_module.h @@ -60,7 +60,7 @@ struct swap_subbuffer; struct buffer_init_t { size_t subbuffer_size; unsigned int nr_subbuffers; - int (*subbuffer_full_cb)(void); + int (*subbuffer_full_cb)(bool wakeup); unsigned char lower_threshold; int (*low_mem_cb)(void); @@ -82,7 +82,7 @@ int swap_buffer_uninit(void); /* SWAP Buffer write function. Pass it size of the data and pointer to the data. * On success returns number of bytes written (>=0) or error code (<0) * otherwise */ -ssize_t swap_buffer_write(void *data, size_t size); +ssize_t swap_buffer_write(void *data, size_t size, bool wakeup); /* SWAP Buffer get. Put subbuffer pointer to the variable *subbuffer. * Return pages count in subbuffer. */ diff --git a/buffer/swap_buffer_to_buffer_queue.h b/buffer/swap_buffer_to_buffer_queue.h index 4d1da3a..076549d 100644 --- a/buffer/swap_buffer_to_buffer_queue.h +++ b/buffer/swap_buffer_to_buffer_queue.h @@ -29,6 +29,8 @@ #ifndef __SWAP_BUFFER_TO_BUFFER_QUEUE_H__ #define __SWAP_BUFFER_TO_BUFFER_QUEUE_H__ -int swap_buffer_callback(void *buffer); +#include + +int swap_buffer_callback(void *buffer, bool wakeup); #endif /* __SWAP_BUFFER_TO_BUFFER_QUEUE_H__ */ diff --git a/driver/driver_to_buffer.c b/driver/driver_to_buffer.c index 2d8e94b..909b3b1 100644 --- a/driver/driver_to_buffer.c +++ b/driver/driver_to_buffer.c @@ -140,16 +140,12 @@ static int driver_to_buffer_release(void) return E_SD_SUCCESS; } -/** - * @brief Buffers callback function - * - * @return 0 - */ -int driver_to_buffer_callback(void) +static int driver_to_buffer_callback(bool wakeup) { /* Increment buffers_to_read counter */ inc_buffers_to_read(); - swap_device_wake_up_process(); + if (wakeup) + swap_device_wake_up_process(); return E_SD_SUCCESS; } diff --git a/driver/driver_to_buffer.h b/driver/driver_to_buffer.h index 200c6bb..e133ee1 100644 --- a/driver/driver_to_buffer.h +++ b/driver/driver_to_buffer.h @@ -33,7 +33,6 @@ int driver_to_buffer_initialize(size_t size, unsigned int count); int driver_to_buffer_uninitialize(void); ssize_t driver_to_buffer_read(char __user *buf, size_t count); -void driver_to_buffer_callback(void); int driver_to_buffer_fill_spd(struct splice_pipe_desc *spd); int driver_to_buffer_buffer_to_read(void); int driver_to_buffer_next_buffer_to_read(void); diff --git a/ks_features/ksf_msg.c b/ks_features/ksf_msg.c index 100fe85..94d2151 100644 --- a/ks_features/ksf_msg.c +++ b/ks_features/ksf_msg.c @@ -360,7 +360,7 @@ static void context_switch(struct pt_regs *regs, enum swap_msg_id id) mcs->tid = task->pid; mcs->cpu_num = smp_processor_id(); - swap_msg_flush(m, sizeof(*mcs)); + swap_msg_flush_wakeupoff(m, sizeof(*mcs)); swap_msg_put(m); } diff --git a/writer/swap_msg.c b/writer/swap_msg.c index 7f496ba..abfd992 100644 --- a/writer/swap_msg.c +++ b/writer/swap_msg.c @@ -119,14 +119,14 @@ struct swap_msg *swap_msg_get(enum swap_msg_id id) } EXPORT_SYMBOL_GPL(swap_msg_get); -int swap_msg_flush(struct swap_msg *m, size_t size) +static int __swap_msg_flush(struct swap_msg *m, size_t size, bool wakeup) { if (unlikely(size >= SWAP_MSG_PAYLOAD_SIZE)) return -ENOMEM; m->len = size; - if (swap_buffer_write(m, SWAP_MSG_PRIV_DATA + size) != + if (swap_buffer_write(m, SWAP_MSG_PRIV_DATA + size, wakeup) != (SWAP_MSG_PRIV_DATA + size)) { atomic_inc(&discarded); return -EINVAL; @@ -134,8 +134,19 @@ int swap_msg_flush(struct swap_msg *m, size_t size) return 0; } + +int swap_msg_flush(struct swap_msg *m, size_t size) +{ + return __swap_msg_flush(m, size, true); +} EXPORT_SYMBOL_GPL(swap_msg_flush); +int swap_msg_flush_wakeupoff(struct swap_msg *m, size_t size) +{ + return __swap_msg_flush(m, size, false); +} +EXPORT_SYMBOL_GPL(swap_msg_flush_wakeupoff); + void swap_msg_put(struct swap_msg *m) { put_cpu(); @@ -350,7 +361,7 @@ int swap_msg_raw(void *data, size_t size) m->seq_num = atomic_inc_return(&seq_num); /* TODO: What should be returned?! When message was discarded. */ - if (swap_buffer_write(m, size) != size) + if (swap_buffer_write(m, size, true) != size) atomic_inc(&discarded); return size; diff --git a/writer/swap_msg.h b/writer/swap_msg.h index afa6dbd..068885d 100644 --- a/writer/swap_msg.h +++ b/writer/swap_msg.h @@ -76,6 +76,7 @@ static inline u64 swap_msg_current_time(void) struct swap_msg *swap_msg_get(enum swap_msg_id id); int swap_msg_flush(struct swap_msg *m, size_t size); +int swap_msg_flush_wakeupoff(struct swap_msg *m, size_t size); void swap_msg_put(struct swap_msg *m); static inline void *swap_msg_payload(struct swap_msg *m)