• Home
  • History
  • Annotate
  • Raw
  • Download
  • only in /netgear-R7000-V1.0.7.12_1.2.5/ap/gpl/hdparm-9.43/

Lines Matching defs:*

2  * Based upon original code by Ric Wheeler and Mark Lord.
4 * Copyright (c) EMC Corporation 2008
5 * Copyright (c) Mark Lord 2008
7 * You may use/distribute this freely, under the terms of either
8 * (your choice) the GNU General Public License version 2,
9 * or a BSD style license.
11 #define _FILE_OFFSET_BITS 64
12 #include <unistd.h>
13 #include <string.h>
14 #include <stdlib.h>
15 #include <stdio.h>
16 #include <fcntl.h>
17 #include <errno.h>
18 #include <sys/ioctl.h>
19 #include <sys/stat.h>
20 #include <linux/types.h>
21 #include <linux/fs.h>
23 #include "hdparm.h"
25 static const unsigned int sector_bytes = 512; // FIXME someday
27 struct file_extent {
28 __u64 byte_offset;
29 __u64 first_block;
30 __u64 last_block;
31 __u64 block_count;
34 static void handle_extent (struct file_extent ext, unsigned int sectors_per_block, __u64 start_lba)
36 char lba_info[64], len_info[32];
37 __u64 begin_lba, end_lba;
38 __u64 nsectors = ext.block_count * sectors_per_block;
40 if (ext.first_block) {
41 begin_lba = start_lba + ( ext.first_block * sectors_per_block);
42 end_lba = start_lba + ((ext.last_block + 1) * sectors_per_block) - 1;
43 } else {
44 begin_lba = end_lba = 0;
47 if (ext.first_block)
48 sprintf(lba_info, "%10llu %10llu", begin_lba, end_lba);
49 else
50 strcpy(lba_info, " - - ");
51 if (!ext.first_block && !nsectors)
52 strcpy(len_info, " - ");
53 else
54 sprintf(len_info, "%10llu", nsectors);
55 printf("%12llu %s %s\n", ext.byte_offset, lba_info, len_info);
58 static int walk_fibmap (int fd, struct stat *st, unsigned int sectors_per_block, __u64 start_lba)
60 struct file_extent ext;
61 unsigned long num_blocks;
62 __u64 blk_idx, hole = ~0ULL;
65 * How many calls to FIBMAP do we need?
66 * FIBMAP returns a filesystem block number (counted from the start of the device)
67 * for each file block. This can be converted to a disk LBA using the filesystem
68 * blocksize and LBA offset obtained earlier.
70 num_blocks = (st->st_size + st->st_blksize - 1) / st->st_blksize;
71 memset(&ext, 0, sizeof(ext));
74 * Loop through the file, building a map of the extents.
75 * All of this is done in filesystem blocks size (fs_blksize) units.
77 * Assumptions:
78 * Throughout the file, there can be any number of blocks backed by holes
79 * or by allocated blocks. Tail-packed files are special - if we find a file
80 * that has a size and has no allocated blocks, we could flag it as a "tail-packed"
81 * file if we cared: data is packed into the tail space of the inode block.
83 for (blk_idx = 0; blk_idx < num_blocks; blk_idx++) {
84 unsigned int blknum = blk_idx;
85 __u64 blknum64;
87 * FIBMAP takes a block index as input and on return replaces it with a
88 * block number relative to the beginning of the filesystem/partition.
89 * An output value of zero means "unallocated", or a "hole" in a sparse file.
90 * Note that this is a 32-bit value, so it will not work properly on
91 * files/filesystems with more than 4 billion blocks (~16TB),
93 if (ioctl(fd, FIBMAP, &blknum) == -1) {
94 int err = errno;
95 perror("ioctl(FIBMAP)");
96 return err;
98 blknum64 = blknum; /* work in 64-bits as much as possible */
100 if (blk_idx && blknum64 == (ext.last_block + 1)) {
102 * Continuation of extent: Bump last_block and block_count.
104 ext.last_block = blknum64 ? blknum64 : hole;
105 ext.block_count++;
106 } else {
108 * New extent: print previous extent (if any), and re-init the extent record.
110 if (blk_idx)
111 handle_extent(ext, sectors_per_block, start_lba);
112 ext.first_block = blknum64;
113 ext.last_block = blknum64 ? blknum64 : hole;
114 ext.block_count = 1;
115 ext.byte_offset = blk_idx * st->st_blksize;
118 handle_extent(ext, sectors_per_block, start_lba);
119 return 0;
122 #define FE_COUNT 8000
123 #define FE_FLAG_LAST (1 << 0)
124 #define FE_FLAG_UNKNOWN (1 << 1)
125 #define FE_FLAG_UNALLOC (1 << 2)
126 #define FE_FLAG_NOALIGN (1 << 8)
128 #define EXTENT_UNKNOWN (FE_FLAG_UNKNOWN | FE_FLAG_UNALLOC | FE_FLAG_NOALIGN)
130 struct fe_s {
131 __u64 logical;
132 __u64 physical;
133 __u64 length;
134 __u64 reserved64[2];
135 __u32 flags;
136 __u32 reserved32[3];
139 struct fm_s {
140 __u64 start;
141 __u64 length;
142 __u32 flags;
143 __u32 mapped_extents;
144 __u32 extent_count;
145 __u32 reserved;
148 struct fs_s {
149 struct fm_s fm;
150 struct fe_s fe[FE_COUNT];
153 #define FIEMAP _IOWR('f', 11, struct fm_s)
155 static int walk_fiemap (int fd, unsigned int sectors_per_block, __u64 start_lba)
157 unsigned int i, done = 0;
158 unsigned int blksize = sectors_per_block * sector_bytes;
159 struct fs_s fs;
161 memset(&fs, 0, sizeof(fs));
162 do {
163 fs.fm.length = ~0ULL;
164 fs.fm.flags = 0;
165 fs.fm.extent_count = FE_COUNT;
167 if (-1 == ioctl(fd, FIEMAP, &fs)) {
168 int err = errno;
169 //perror("ioctl(FIEMAP)");
170 return err;
173 if (0) fprintf(stderr, "ioctl(FIEMAP) returned %llu extents\n", (__u64)fs.fm.mapped_extents);
174 if (!fs.fm.mapped_extents) {
175 done = 1;
176 } else {
177 struct file_extent ext;
178 memset(&ext, 0, sizeof(ext));
179 for (i = 0; i < fs.fm.mapped_extents; i++) {
180 __u64 phy_blk, ext_len;
182 ext.byte_offset = fs.fe[i].logical;
183 if (0) fprintf(stderr, "log=%llu phy=%llu len=%llu flags=0x%x\n", fs.fe[i].logical,
184 fs.fe[i].physical, fs.fe[i].length, fs.fe[i].flags);
185 if (fs.fe[i].flags & EXTENT_UNKNOWN) {
186 ext.first_block = 0;
187 ext.last_block = 0;
188 ext.block_count = 0; /* FIEMAP returns garbage for this. Ugh. */
189 } else {
190 phy_blk = fs.fe[i].physical / blksize;
191 ext_len = fs.fe[i].length / blksize;
193 ext.first_block = phy_blk;
194 ext.last_block = phy_blk + ext_len - 1;
195 ext.block_count = ext_len;
197 handle_extent(ext, sectors_per_block, start_lba);
199 if (fs.fe[i].flags & FE_FLAG_LAST) {
201 * Hit an ext4 bug in 2.6.29.4, where some FIEMAP calls
202 * had the LAST flag set in the final returned extent,
203 * even though there were *plenty* more extents to be had
204 * from continued FIEMAP calls.
206 * So, we'll ignore it here, and instead rely on getting
207 * a zero count back from fs.fm.mapped_extents at the end.
209 if (0) fprintf(stderr, "%s: ignoring LAST bit\n", __func__);
210 //done = 1;
214 fs.fm.start = (fs.fe[i-1].logical + fs.fe[i-1].length);
216 } while (!done);
217 return 0;
220 int do_filemap (const char *file_name)
222 int fd, err;
223 struct stat st;
224 __u64 start_lba = 0;
225 unsigned int sectors_per_block, blksize;
227 if ((fd = open(file_name, O_RDONLY)) == -1) {
228 err = errno;
229 perror(file_name);
230 return err;
232 if (fstat(fd, &st) == -1) {
233 err = errno;
234 perror(file_name);
235 return err;
237 if (!S_ISREG(st.st_mode)) {
238 fprintf(stderr, "%s: not a regular file\n", file_name);
239 close(fd);
240 return EINVAL;
244 * Get the filesystem starting LBA:
246 err = get_dev_t_geometry(st.st_dev, NULL, NULL, NULL, &start_lba, NULL);
247 if (err) {
248 close(fd);
249 return err;
251 if (start_lba == START_LBA_UNKNOWN) {
252 fprintf(stderr, "Unable to determine start offset LBA for device, aborting.\n");
253 close(fd);
254 return EIO;
256 if((err=ioctl(fd,FIGETBSZ,&blksize))){
257 fprintf(stderr, "Unable to determine block size, aborting.\n");
258 close(fd);
259 return err;
261 sectors_per_block = blksize / sector_bytes;
262 printf("\n%s:\n filesystem blocksize %u, begins at LBA %llu;"
263 " assuming %u byte sectors.\n",
264 file_name, blksize, start_lba, sector_bytes);
265 printf("%12s %10s %10s %10s\n", "byte_offset", "begin_LBA", "end_LBA", "sectors");
267 if (st.st_size == 0) {
268 struct file_extent ext;
269 memset(&ext, 0, sizeof(ext));
270 handle_extent(ext, sectors_per_block, start_lba);
271 close(fd);
272 return 0;
275 err = walk_fiemap(fd, sectors_per_block, start_lba);
276 if (err)
277 err = walk_fibmap(fd, &st, sectors_per_block, start_lba);
278 close (fd);
279 return 0;