/
page-read.c
162 lines (139 loc) · 3.77 KB
/
page-read.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
/**
* @file page-read.c
* @brief read logic for page ftl
* @author Gijun Oh
* @version 0.2
* @date 2021-09-22
*/
#include "page.h"
#include "log.h"
#include "lru.h"
#include <errno.h>
#include <stdlib.h>
#include <string.h>
/**
* @brief read's end request function
*
* @param request the request which is submitted before
*/
static void page_ftl_read_end_rq(struct device_request *read_rq)
{
struct device_request *request;
struct page_ftl *pgftl;
size_t offset;
request = (struct device_request *)read_rq->rq_private;
pgftl = (struct page_ftl *)request->rq_private;
offset = page_ftl_get_page_offset(pgftl, request->sector);
memcpy(request->data, &((char *)read_rq->data)[offset],
request->data_len);
free(read_rq->data);
device_free_request(read_rq);
pthread_mutex_lock(&request->mutex);
if (g_atomic_int_get(&request->is_finish) == 0) {
pthread_cond_signal(&request->cond);
}
g_atomic_int_set(&request->is_finish, 1);
pthread_mutex_unlock(&request->mutex);
}
/**
* @brief the core logic for reading the request to the device.
*
* @param pgftl pointer of the page FTL structure
* @param request user's request pointer
*
* @return reading data size. a negative number means fail to read.
* @note
* if paddr.lpn doesn't exist, this function returns the buffer filled 0 value.
*/
ssize_t page_ftl_read(struct page_ftl *pgftl, struct device_request *request)
{
struct device *dev;
struct device_request *read_rq;
struct device_address paddr;
#ifdef PAGE_FTL_USE_CACHE
struct device_request *cached;
#endif
char *buffer;
size_t page_size;
size_t lpn, offset;
ssize_t ret = 0;
ssize_t data_len;
buffer = NULL;
read_rq = NULL;
dev = pgftl->dev;
page_size = device_get_page_size(dev);
lpn = page_ftl_get_lpn(pgftl, request->sector);
offset = page_ftl_get_page_offset(pgftl, request->sector);
pthread_mutex_lock(&pgftl->mutex);
paddr.lpn = pgftl->trans_map[lpn];
#ifdef PAGE_FTL_USE_CACHE
cached = (struct device_request *)lru_get(pgftl->cache, lpn);
if (cached) {
memcpy(request->data, &((char *)cached->data)[offset],
request->data_len);
ret = request->data_len;
device_free_request(request);
pthread_mutex_unlock(&pgftl->mutex);
goto exception;
}
#endif
pthread_mutex_unlock(&pgftl->mutex);
if (paddr.lpn == PADDR_EMPTY) { /**< YOU MUST TAKE CARE OF THIS LINE */
pr_warn("cannot find the mapping information (lpn: %zu)\n",
lpn);
memset(request->data, 0, request->data_len);
ret = request->data_len;
device_free_request(request);
goto exception;
}
request->rq_private = pgftl;
if (offset + request->data_len > page_size) {
pr_err("overflow the read data (offset: %zu, length: %zu)\n",
offset, request->data_len);
ret = -EINVAL;
goto exception;
}
buffer = (char *)malloc(page_size);
if (buffer == NULL) {
pr_err("memory allocation failed\n");
ret = -ENOMEM;
goto exception;
}
memset(buffer, 0, page_size);
read_rq = device_alloc_request(DEVICE_DEFAULT_REQUEST);
if (read_rq == NULL) {
pr_err("request allocation failed\n");
ret = -ENOMEM;
goto exception;
}
read_rq->flag = DEVICE_READ;
read_rq->data = buffer;
read_rq->data_len = page_size;
read_rq->paddr = paddr;
read_rq->rq_private = request;
read_rq->end_rq = page_ftl_read_end_rq;
data_len = request->data_len;
ret = dev->d_op->read(dev, read_rq);
if (ret < 0) {
pr_err("device read failed (ppn: %u)\n", request->paddr.lpn);
read_rq = NULL;
buffer = NULL;
goto exception;
}
pthread_mutex_lock(&request->mutex);
while (g_atomic_int_get(&request->is_finish) == 0) {
pthread_cond_wait(&request->cond, &request->mutex);
}
pthread_mutex_unlock(&request->mutex);
device_free_request(request);
ret = data_len;
return ret;
exception:
if (buffer) {
free(buffer);
}
if (read_rq) {
device_free_request(read_rq);
}
return ret;
}