source: bootcd/isolinux/syslinux-6.03/core/fs/getfssec.c

Last change on this file was e16e8f2, checked in by Edwin Eefting <edwin@datux.nl>, 3 years ago

bootstuff

  • Property mode set to 100644
File size: 6.1 KB
Line 
1/* ----------------------------------------------------------------------- *
2 *
3 *   Copyright 2010 Intel Corporation; author: H. Peter Anvin
4 *
5 *   Permission is hereby granted, free of charge, to any person
6 *   obtaining a copy of this software and associated documentation
7 *   files (the "Software"), to deal in the Software without
8 *   restriction, including without limitation the rights to use,
9 *   copy, modify, merge, publish, distribute, sublicense, and/or
10 *   sell copies of the Software, and to permit persons to whom
11 *   the Software is furnished to do so, subject to the following
12 *   conditions:
13 *
14 *   The above copyright notice and this permission notice shall
15 *   be included in all copies or substantial portions of the Software.
16 *
17 *   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
18 *   EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
19 *   OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
20 *   NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
21 *   HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
22 *   WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
23 *   FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
24 *   OTHER DEALINGS IN THE SOFTWARE.
25 *
26 * ----------------------------------------------------------------------- */
27
28/*
29 * getfssec.c
30 *
31 * Generic getfssec implementation for disk-based filesystems, which
32 * support the next_extent() method.
33 *
34 * The expected semantics of next_extent are as follows:
35 *
36 * The second argument will contain the initial sector number to be
37 * mapped.  The routine is expected to populate
38 * inode->next_extent.pstart and inode->next_extent.len (the caller
39 * will store the initial sector number into inode->next_extent.lstart
40 * on return.)
41 *
42 * If inode->next_extent.len != 0 on entry then the routine is allowed
43 * to assume inode->next_extent contains valid data from the previous
44 * usage, which can be used for optimization purposes.
45 *
46 * If the filesystem can map the entire file as a single extent
47 * (e.g. iso9660), then the filesystem can simply insert the extent
48 * information into inode->next_extent at searchdir/iget time, and leave
49 * next_extent() as NULL.
50 *
51 * Note: the filesystem driver is not required to do extent coalescing,
52 * if that is difficult to do; this routine will perform extent lookahead
53 * and coalescing.
54 */
55
56#include <dprintf.h>
57#include <minmax.h>
58#include "fs.h"
59
60static inline sector_t next_psector(sector_t psector, uint32_t skip)
61{
62    if (EXTENT_SPECIAL(psector))
63        return psector;
64    else
65        return psector + skip;
66}
67
68static inline sector_t next_pstart(const struct extent *e)
69{
70    return next_psector(e->pstart, e->len);
71}
72
73
74static void get_next_extent(struct inode *inode)
75{
76    /* The logical start address that we care about... */
77    uint32_t lstart = inode->this_extent.lstart + inode->this_extent.len;
78
79    if (inode->fs->fs_ops->next_extent(inode, lstart))
80        inode->next_extent.len = 0; /* ERROR */
81    inode->next_extent.lstart = lstart;
82
83    dprintf("Extent: inode %p @ %u start %llu len %u\n",
84            inode, inode->next_extent.lstart,
85            inode->next_extent.pstart, inode->next_extent.len);
86}
87
88uint32_t generic_getfssec(struct file *file, char *buf,
89                          int sectors, bool *have_more)
90{
91    struct inode *inode = file->inode;
92    struct fs_info *fs = file->fs;
93    struct disk *disk = fs->fs_dev->disk;
94    uint32_t bytes_read = 0;
95    uint32_t bytes_left = inode->size - file->offset;
96    uint32_t sectors_left =
97        (bytes_left + SECTOR_SIZE(fs) - 1) >> SECTOR_SHIFT(fs);
98    uint32_t lsector;
99
100    if (sectors > sectors_left)
101        sectors = sectors_left;
102
103    if (!sectors)
104        return 0;
105
106    lsector = file->offset >> SECTOR_SHIFT(fs);
107    dprintf("Offset: %u  lsector: %u\n", file->offset, lsector);
108
109    if (lsector < inode->this_extent.lstart ||
110        lsector >= inode->this_extent.lstart + inode->this_extent.len) {
111        /* inode->this_extent unusable, maybe next_extent is... */
112        inode->this_extent = inode->next_extent;
113    }
114
115    if (lsector < inode->this_extent.lstart ||
116        lsector >= inode->this_extent.lstart + inode->this_extent.len) {
117        /* Still nothing useful... */
118        inode->this_extent.lstart = lsector;
119        inode->this_extent.len = 0;
120    } else {
121        /* We have some usable information */
122        uint32_t delta = lsector - inode->this_extent.lstart;
123        inode->this_extent.lstart = lsector;
124        inode->this_extent.len -= delta;
125        inode->this_extent.pstart
126            = next_psector(inode->this_extent.pstart, delta);
127    }
128
129    dprintf("this_extent: lstart %u pstart %llu len %u\n",
130            inode->this_extent.lstart,
131            inode->this_extent.pstart,
132            inode->this_extent.len);
133
134    while (sectors) {
135        uint32_t chunk;
136        size_t len;
137
138        while (sectors > inode->this_extent.len) {
139            if (!inode->next_extent.len ||
140                inode->next_extent.lstart !=
141                inode->this_extent.lstart + inode->this_extent.len)
142                get_next_extent(inode);
143
144            if (!inode->this_extent.len) {
145                /* Doesn't matter if it's contiguous... */
146                inode->this_extent = inode->next_extent;
147                if (!inode->next_extent.len) {
148                    sectors = 0; /* Failed to get anything... we're dead */
149                    break;
150                }
151            } else if (inode->next_extent.len &&
152                inode->next_extent.pstart == next_pstart(&inode->this_extent)) {
153                /* Coalesce extents and loop */
154                inode->this_extent.len += inode->next_extent.len;
155            } else {
156                /* Discontiguous extents */
157                break;
158            }
159        }
160
161        dprintf("this_extent: lstart %u pstart %llu len %u\n",
162                inode->this_extent.lstart,
163                inode->this_extent.pstart,
164                inode->this_extent.len);
165
166        chunk = min(sectors, inode->this_extent.len);
167        len = chunk << SECTOR_SHIFT(fs);
168
169        dprintf("   I/O: inode %p @ %u start %llu len %u\n",
170                inode, inode->this_extent.lstart,
171                inode->this_extent.pstart, chunk);
172
173        if (inode->this_extent.pstart == EXTENT_ZERO) {
174            memset(buf, 0, len);
175        } else {
176            disk->rdwr_sectors(disk, buf, inode->this_extent.pstart, chunk, 0);
177            inode->this_extent.pstart += chunk;
178        }
179
180        buf += len;
181        sectors -= chunk;
182        bytes_read += len;
183        inode->this_extent.lstart += chunk;
184        inode->this_extent.len -= chunk;
185    }
186
187    bytes_read = min(bytes_read, bytes_left);
188    file->offset += bytes_read;
189
190    if (have_more)
191        *have_more = bytes_read < bytes_left;
192
193    return bytes_read;
194}
Note: See TracBrowser for help on using the repository browser.