]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/dev/nand/nandsim_swap.c
FCP-101: Remove ex(4).
[FreeBSD/FreeBSD.git] / sys / dev / nand / nandsim_swap.c
1 /*-
2  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3  *
4  * Copyright (C) 2009-2012 Semihalf
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26  * SUCH DAMAGE.
27  */
28
29 #include <sys/cdefs.h>
30 __FBSDID("$FreeBSD$");
31
32 #include <sys/param.h>
33 #include <sys/types.h>
34 #include <sys/systm.h>
35 #include <sys/malloc.h>
36 #include <sys/queue.h>
37 #include <sys/fcntl.h>
38 #include <sys/proc.h>
39 #include <sys/namei.h>
40 #include <sys/lock.h>
41 #include <sys/vnode.h>
42 #include <sys/mount.h>
43
44 #include <dev/nand/nandsim_chip.h>
45 #include <dev/nand/nandsim_swap.h>
46
47 static int  init_block_state(struct chip_swap *);
48 static void destroy_block_state(struct chip_swap *);
49
50 static int  create_buffers(struct chip_swap *);
51 static void destroy_buffers(struct chip_swap *);
52
53 static int  swap_file_open(struct chip_swap *, const char *);
54 static void swap_file_close(struct chip_swap *);
55 static int  swap_file_write(struct chip_swap *, struct block_state *);
56 static int  swap_file_read(struct chip_swap *, struct block_state *);
57
58 #define CHIP_SWAP_CMODE         0600
59 #define CHIP_SWAP_BLOCKSPACES   2
60
61 static int
62 init_block_state(struct chip_swap *swap)
63 {
64         struct block_state *blk_state;
65         int i;
66
67         if (swap == NULL)
68                 return (-1);
69
70         blk_state = malloc(swap->nof_blks * sizeof(struct block_state),
71             M_NANDSIM, M_WAITOK | M_ZERO);
72
73         for (i = 0; i < swap->nof_blks; i++)
74                 blk_state[i].offset = 0xffffffff;
75
76         swap->blk_state = blk_state;
77
78         return (0);
79 }
80
81 static void
82 destroy_block_state(struct chip_swap *swap)
83 {
84
85         if (swap == NULL)
86                 return;
87
88         if (swap->blk_state != NULL)
89                 free(swap->blk_state, M_NANDSIM);
90 }
91
92 static int
93 create_buffers(struct chip_swap *swap)
94 {
95         struct block_space *block_space;
96         void *block;
97         int i;
98
99         for (i = 0; i < CHIP_SWAP_BLOCKSPACES; i++) {
100                 block_space = malloc(sizeof(*block_space), M_NANDSIM, M_WAITOK);
101                 block = malloc(swap->blk_size, M_NANDSIM, M_WAITOK);
102                 block_space->blk_ptr = block;
103                 SLIST_INSERT_HEAD(&swap->free_bs, block_space, free_link);
104                 nand_debug(NDBG_SIM,"created blk_space %p[%p]\n", block_space,
105                     block);
106         }
107
108         if (i == 0)
109                 return (-1);
110
111         return (0);
112 }
113
114 static void
115 destroy_buffers(struct chip_swap *swap)
116 {
117         struct block_space *blk_space;
118
119         if (swap == NULL)
120                 return;
121
122         blk_space = SLIST_FIRST(&swap->free_bs);
123         while (blk_space) {
124                 SLIST_REMOVE_HEAD(&swap->free_bs, free_link);
125                 nand_debug(NDBG_SIM,"destroyed blk_space %p[%p]\n",
126                     blk_space, blk_space->blk_ptr);
127                 free(blk_space->blk_ptr, M_NANDSIM);
128                 free(blk_space, M_NANDSIM);
129                 blk_space = SLIST_FIRST(&swap->free_bs);
130         }
131
132         blk_space = STAILQ_FIRST(&swap->used_bs);
133         while (blk_space) {
134                 STAILQ_REMOVE_HEAD(&swap->used_bs, used_link);
135                 nand_debug(NDBG_SIM,"destroyed blk_space %p[%p]\n",
136                     blk_space, blk_space->blk_ptr);
137                 free(blk_space->blk_ptr, M_NANDSIM);
138                 free(blk_space, M_NANDSIM);
139                 blk_space = STAILQ_FIRST(&swap->used_bs);
140         }
141 }
142
143 static int
144 swap_file_open(struct chip_swap *swap, const char *swap_file)
145 {
146         struct nameidata nd;
147         int flags, error;
148
149         NDINIT(&nd, LOOKUP, NOFOLLOW, UIO_SYSSPACE, swap_file,
150             curthread);
151
152         flags = FWRITE | FREAD | O_NOFOLLOW | O_CREAT | O_TRUNC;
153
154         error = vn_open(&nd, &flags, CHIP_SWAP_CMODE, NULL);
155         if (error) {
156                 nand_debug(NDBG_SIM,"Cannot create swap file %s", swap_file);
157                 NDFREE(&nd, NDF_ONLY_PNBUF);
158                 return (error);
159         }
160
161         swap->swap_cred = crhold(curthread->td_ucred);
162         NDFREE(&nd, NDF_ONLY_PNBUF);
163
164         /* We just unlock so we hold a reference */
165         VOP_UNLOCK(nd.ni_vp, 0);
166
167         swap->swap_vp = nd.ni_vp;
168
169         return (0);
170 }
171
172 static void
173 swap_file_close(struct chip_swap *swap)
174 {
175
176         if (swap == NULL)
177                 return;
178
179         if (swap->swap_vp == NULL)
180                 return;
181
182         vn_close(swap->swap_vp, FWRITE, swap->swap_cred, curthread);
183         crfree(swap->swap_cred);
184 }
185
186 static int
187 swap_file_write(struct chip_swap *swap, struct block_state *blk_state)
188 {
189         struct block_space *blk_space;
190         struct thread *td;
191         struct mount *mp;
192         struct vnode *vp;
193         struct uio auio;
194         struct iovec aiov;
195
196         if (swap == NULL || blk_state == NULL)
197                 return (-1);
198
199         blk_space = blk_state->blk_sp;
200         if (blk_state->offset == -1) {
201                 blk_state->offset = swap->swap_offset;
202                 swap->swap_offset += swap->blk_size;
203         }
204
205         nand_debug(NDBG_SIM,"saving %p[%p] at %x\n",
206             blk_space, blk_space->blk_ptr, blk_state->offset);
207
208         bzero(&aiov, sizeof(aiov));
209         bzero(&auio, sizeof(auio));
210
211         aiov.iov_base = blk_space->blk_ptr;
212         aiov.iov_len = swap->blk_size;
213         td = curthread;
214         vp = swap->swap_vp;
215
216         auio.uio_iov = &aiov;
217         auio.uio_offset = blk_state->offset;
218         auio.uio_segflg = UIO_SYSSPACE;
219         auio.uio_rw = UIO_WRITE;
220         auio.uio_iovcnt = 1;
221         auio.uio_resid = swap->blk_size;
222         auio.uio_td = td;
223
224         vn_start_write(vp, &mp, V_WAIT);
225         vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
226         VOP_WRITE(vp, &auio, IO_UNIT, swap->swap_cred);
227         VOP_UNLOCK(vp, 0);
228         vn_finished_write(mp);
229
230         return (0);
231 }
232
233 static int
234 swap_file_read(struct chip_swap *swap, struct block_state *blk_state)
235 {
236         struct block_space *blk_space;
237         struct thread *td;
238         struct vnode *vp;
239         struct uio auio;
240         struct iovec aiov;
241
242         if (swap == NULL || blk_state == NULL)
243                 return (-1);
244
245         blk_space = blk_state->blk_sp;
246
247         nand_debug(NDBG_SIM,"restore %p[%p] at %x\n",
248             blk_space, blk_space->blk_ptr, blk_state->offset);
249
250         bzero(&aiov, sizeof(aiov));
251         bzero(&auio, sizeof(auio));
252
253         aiov.iov_base = blk_space->blk_ptr;
254         aiov.iov_len = swap->blk_size;
255         td = curthread;
256         vp = swap->swap_vp;
257
258         auio.uio_iov = &aiov;
259         auio.uio_offset = blk_state->offset;
260         auio.uio_segflg = UIO_SYSSPACE;
261         auio.uio_rw = UIO_READ;
262         auio.uio_iovcnt = 1;
263         auio.uio_resid = swap->blk_size;
264         auio.uio_td = td;
265
266         vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
267         VOP_READ(vp, &auio, 0, swap->swap_cred);
268         VOP_UNLOCK(vp, 0);
269
270         return (0);
271 }
272
273 struct chip_swap *
274 nandsim_swap_init(const char *swap_file, uint32_t nof_blks, uint32_t blk_size)
275 {
276         struct chip_swap *swap;
277         int err = 0;
278
279         if ((swap_file == NULL) || (nof_blks == 0) || (blk_size == 0))
280                 return (NULL);
281
282         swap = malloc(sizeof(*swap), M_NANDSIM, M_WAITOK | M_ZERO);
283
284         SLIST_INIT(&swap->free_bs);
285         STAILQ_INIT(&swap->used_bs);
286         swap->blk_size = blk_size;
287         swap->nof_blks = nof_blks;
288
289         err = init_block_state(swap);
290         if (err) {
291                 nandsim_swap_destroy(swap);
292                 return (NULL);
293         }
294
295         err = create_buffers(swap);
296         if (err) {
297                 nandsim_swap_destroy(swap);
298                 return (NULL);
299         }
300
301         err = swap_file_open(swap, swap_file);
302         if (err) {
303                 nandsim_swap_destroy(swap);
304                 return (NULL);
305         }
306
307         return (swap);
308 }
309
310 void
311 nandsim_swap_destroy(struct chip_swap *swap)
312 {
313
314         if (swap == NULL)
315                 return;
316
317         destroy_block_state(swap);
318         destroy_buffers(swap);
319         swap_file_close(swap);
320         free(swap, M_NANDSIM);
321 }
322
323 struct block_space *
324 get_bs(struct chip_swap *swap, uint32_t block, uint8_t writing)
325 {
326         struct block_state *blk_state, *old_blk_state = NULL;
327         struct block_space *blk_space;
328
329         if (swap == NULL || (block >= swap->nof_blks))
330                 return (NULL);
331
332         blk_state = &swap->blk_state[block];
333         nand_debug(NDBG_SIM,"blk_state %x\n", blk_state->status);
334
335         if (blk_state->status & BLOCK_ALLOCATED) {
336                 blk_space = blk_state->blk_sp;
337         } else {
338                 blk_space = SLIST_FIRST(&swap->free_bs);
339                 if (blk_space) {
340                         SLIST_REMOVE_HEAD(&swap->free_bs, free_link);
341                         STAILQ_INSERT_TAIL(&swap->used_bs, blk_space,
342                             used_link);
343                 } else {
344                         blk_space = STAILQ_FIRST(&swap->used_bs);
345                         old_blk_state = blk_space->blk_state;
346                         STAILQ_REMOVE_HEAD(&swap->used_bs, used_link);
347                         STAILQ_INSERT_TAIL(&swap->used_bs, blk_space,
348                             used_link);
349                         if (old_blk_state->status & BLOCK_DIRTY) {
350                                 swap_file_write(swap, old_blk_state);
351                                 old_blk_state->status &= ~BLOCK_DIRTY;
352                                 old_blk_state->status |= BLOCK_SWAPPED;
353                         }
354                 }
355         }
356
357         if (blk_space == NULL)
358                 return (NULL);
359
360         if (old_blk_state != NULL) {
361                 old_blk_state->status &= ~BLOCK_ALLOCATED;
362                 old_blk_state->blk_sp = NULL;
363         }
364
365         blk_state->blk_sp = blk_space;
366         blk_space->blk_state = blk_state;
367
368         if (!(blk_state->status & BLOCK_ALLOCATED)) {
369                 if (blk_state->status & BLOCK_SWAPPED)
370                         swap_file_read(swap, blk_state);
371                 else
372                         memset(blk_space->blk_ptr, 0xff, swap->blk_size);
373                 blk_state->status |= BLOCK_ALLOCATED;
374         }
375
376         if (writing)
377                 blk_state->status |= BLOCK_DIRTY;
378
379         nand_debug(NDBG_SIM,"get_bs returned %p[%p] state %x\n", blk_space,
380             blk_space->blk_ptr, blk_state->status);
381
382         return (blk_space);
383 }