tools headers UAPI: Sync openat2.h with the kernel sources
[linux-2.6-microblaze.git] / fs / squashfs / page_actor.c
1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3  * Copyright (c) 2013
4  * Phillip Lougher <phillip@squashfs.org.uk>
5  */
6
7 #include <linux/kernel.h>
8 #include <linux/slab.h>
9 #include <linux/pagemap.h>
10 #include "page_actor.h"
11
12 /*
13  * This file contains implementations of page_actor for decompressing into
14  * an intermediate buffer, and for decompressing directly into the
15  * page cache.
16  *
17  * Calling code should avoid sleeping between calls to squashfs_first_page()
18  * and squashfs_finish_page().
19  */
20
21 /* Implementation of page_actor for decompressing into intermediate buffer */
22 static void *cache_first_page(struct squashfs_page_actor *actor)
23 {
24         actor->next_page = 1;
25         return actor->buffer[0];
26 }
27
28 static void *cache_next_page(struct squashfs_page_actor *actor)
29 {
30         if (actor->next_page == actor->pages)
31                 return NULL;
32
33         return actor->buffer[actor->next_page++];
34 }
35
36 static void cache_finish_page(struct squashfs_page_actor *actor)
37 {
38         /* empty */
39 }
40
41 struct squashfs_page_actor *squashfs_page_actor_init(void **buffer,
42         int pages, int length)
43 {
44         struct squashfs_page_actor *actor = kmalloc(sizeof(*actor), GFP_KERNEL);
45
46         if (actor == NULL)
47                 return NULL;
48
49         actor->length = length ? : pages * PAGE_SIZE;
50         actor->buffer = buffer;
51         actor->pages = pages;
52         actor->next_page = 0;
53         actor->squashfs_first_page = cache_first_page;
54         actor->squashfs_next_page = cache_next_page;
55         actor->squashfs_finish_page = cache_finish_page;
56         return actor;
57 }
58
59 /* Implementation of page_actor for decompressing directly into page cache. */
60 static void *direct_first_page(struct squashfs_page_actor *actor)
61 {
62         actor->next_page = 1;
63         return actor->pageaddr = kmap_atomic(actor->page[0]);
64 }
65
66 static void *direct_next_page(struct squashfs_page_actor *actor)
67 {
68         if (actor->pageaddr)
69                 kunmap_atomic(actor->pageaddr);
70
71         return actor->pageaddr = actor->next_page == actor->pages ? NULL :
72                 kmap_atomic(actor->page[actor->next_page++]);
73 }
74
75 static void direct_finish_page(struct squashfs_page_actor *actor)
76 {
77         if (actor->pageaddr)
78                 kunmap_atomic(actor->pageaddr);
79 }
80
81 struct squashfs_page_actor *squashfs_page_actor_init_special(struct page **page,
82         int pages, int length)
83 {
84         struct squashfs_page_actor *actor = kmalloc(sizeof(*actor), GFP_KERNEL);
85
86         if (actor == NULL)
87                 return NULL;
88
89         actor->length = length ? : pages * PAGE_SIZE;
90         actor->page = page;
91         actor->pages = pages;
92         actor->next_page = 0;
93         actor->pageaddr = NULL;
94         actor->squashfs_first_page = direct_first_page;
95         actor->squashfs_next_page = direct_next_page;
96         actor->squashfs_finish_page = direct_finish_page;
97         return actor;
98 }