xref: /openbmc/linux/fs/romfs/storage.c (revision da4458bd)
1da4458bdSDavid Howells /* RomFS storage access routines
2da4458bdSDavid Howells  *
3da4458bdSDavid Howells  * Copyright © 2007 Red Hat, Inc. All Rights Reserved.
4da4458bdSDavid Howells  * Written by David Howells (dhowells@redhat.com)
5da4458bdSDavid Howells  *
6da4458bdSDavid Howells  * This program is free software; you can redistribute it and/or
7da4458bdSDavid Howells  * modify it under the terms of the GNU General Public License
8da4458bdSDavid Howells  * as published by the Free Software Foundation; either version
9da4458bdSDavid Howells  * 2 of the License, or (at your option) any later version.
10da4458bdSDavid Howells  */
11da4458bdSDavid Howells 
12da4458bdSDavid Howells #include <linux/fs.h>
13da4458bdSDavid Howells #include <linux/mtd/super.h>
14da4458bdSDavid Howells #include <linux/buffer_head.h>
15da4458bdSDavid Howells #include "internal.h"
16da4458bdSDavid Howells 
17da4458bdSDavid Howells #if !defined(CONFIG_ROMFS_ON_MTD) && !defined(CONFIG_ROMFS_ON_BLOCK)
18da4458bdSDavid Howells #error no ROMFS backing store interface configured
19da4458bdSDavid Howells #endif
20da4458bdSDavid Howells 
21da4458bdSDavid Howells #ifdef CONFIG_ROMFS_ON_MTD
22da4458bdSDavid Howells #define ROMFS_MTD_READ(sb, ...) ((sb)->s_mtd->read((sb)->s_mtd, ##__VA_ARGS__))
23da4458bdSDavid Howells 
24da4458bdSDavid Howells /*
25da4458bdSDavid Howells  * read data from an romfs image on an MTD device
26da4458bdSDavid Howells  */
27da4458bdSDavid Howells static int romfs_mtd_read(struct super_block *sb, unsigned long pos,
28da4458bdSDavid Howells 			  void *buf, size_t buflen)
29da4458bdSDavid Howells {
30da4458bdSDavid Howells 	size_t rlen;
31da4458bdSDavid Howells 	int ret;
32da4458bdSDavid Howells 
33da4458bdSDavid Howells 	ret = ROMFS_MTD_READ(sb, pos, buflen, &rlen, buf);
34da4458bdSDavid Howells 	return (ret < 0 || rlen != buflen) ? -EIO : 0;
35da4458bdSDavid Howells }
36da4458bdSDavid Howells 
37da4458bdSDavid Howells /*
38da4458bdSDavid Howells  * determine the length of a string in a romfs image on an MTD device
39da4458bdSDavid Howells  */
40da4458bdSDavid Howells static ssize_t romfs_mtd_strnlen(struct super_block *sb,
41da4458bdSDavid Howells 				 unsigned long pos, size_t maxlen)
42da4458bdSDavid Howells {
43da4458bdSDavid Howells 	ssize_t n = 0;
44da4458bdSDavid Howells 	size_t segment;
45da4458bdSDavid Howells 	u_char buf[16], *p;
46da4458bdSDavid Howells 	size_t len;
47da4458bdSDavid Howells 	int ret;
48da4458bdSDavid Howells 
49da4458bdSDavid Howells 	/* scan the string up to 16 bytes at a time */
50da4458bdSDavid Howells 	while (maxlen > 0) {
51da4458bdSDavid Howells 		segment = min_t(size_t, maxlen, 16);
52da4458bdSDavid Howells 		ret = ROMFS_MTD_READ(sb, pos, segment, &len, buf);
53da4458bdSDavid Howells 		if (ret < 0)
54da4458bdSDavid Howells 			return ret;
55da4458bdSDavid Howells 		p = memchr(buf, 0, len);
56da4458bdSDavid Howells 		if (p)
57da4458bdSDavid Howells 			return n + (p - buf);
58da4458bdSDavid Howells 		maxlen -= len;
59da4458bdSDavid Howells 		pos += len;
60da4458bdSDavid Howells 		n += len;
61da4458bdSDavid Howells 	}
62da4458bdSDavid Howells 
63da4458bdSDavid Howells 	return n;
64da4458bdSDavid Howells }
65da4458bdSDavid Howells 
66da4458bdSDavid Howells /*
67da4458bdSDavid Howells  * compare a string to one in a romfs image on MTD
68da4458bdSDavid Howells  * - return 1 if matched, 0 if differ, -ve if error
69da4458bdSDavid Howells  */
70da4458bdSDavid Howells static int romfs_mtd_strncmp(struct super_block *sb, unsigned long pos,
71da4458bdSDavid Howells 			     const char *str, size_t size)
72da4458bdSDavid Howells {
73da4458bdSDavid Howells 	u_char buf[16];
74da4458bdSDavid Howells 	size_t len, segment;
75da4458bdSDavid Howells 	int ret;
76da4458bdSDavid Howells 
77da4458bdSDavid Howells 	/* scan the string up to 16 bytes at a time */
78da4458bdSDavid Howells 	while (size > 0) {
79da4458bdSDavid Howells 		segment = min_t(size_t, size, 16);
80da4458bdSDavid Howells 		ret = ROMFS_MTD_READ(sb, pos, segment, &len, buf);
81da4458bdSDavid Howells 		if (ret < 0)
82da4458bdSDavid Howells 			return ret;
83da4458bdSDavid Howells 		if (memcmp(buf, str, len) != 0)
84da4458bdSDavid Howells 			return 0;
85da4458bdSDavid Howells 		size -= len;
86da4458bdSDavid Howells 		pos += len;
87da4458bdSDavid Howells 		str += len;
88da4458bdSDavid Howells 	}
89da4458bdSDavid Howells 
90da4458bdSDavid Howells 	return 1;
91da4458bdSDavid Howells }
92da4458bdSDavid Howells #endif /* CONFIG_ROMFS_ON_MTD */
93da4458bdSDavid Howells 
94da4458bdSDavid Howells #ifdef CONFIG_ROMFS_ON_BLOCK
95da4458bdSDavid Howells /*
96da4458bdSDavid Howells  * read data from an romfs image on a block device
97da4458bdSDavid Howells  */
98da4458bdSDavid Howells static int romfs_blk_read(struct super_block *sb, unsigned long pos,
99da4458bdSDavid Howells 			  void *buf, size_t buflen)
100da4458bdSDavid Howells {
101da4458bdSDavid Howells 	struct buffer_head *bh;
102da4458bdSDavid Howells 	unsigned long offset;
103da4458bdSDavid Howells 	size_t segment;
104da4458bdSDavid Howells 
105da4458bdSDavid Howells 	/* copy the string up to blocksize bytes at a time */
106da4458bdSDavid Howells 	while (buflen > 0) {
107da4458bdSDavid Howells 		offset = pos & (ROMBSIZE - 1);
108da4458bdSDavid Howells 		segment = min_t(size_t, buflen, ROMBSIZE - offset);
109da4458bdSDavid Howells 		bh = sb_bread(sb, pos >> ROMBSBITS);
110da4458bdSDavid Howells 		if (!bh)
111da4458bdSDavid Howells 			return -EIO;
112da4458bdSDavid Howells 		memcpy(buf, bh->b_data + offset, segment);
113da4458bdSDavid Howells 		brelse(bh);
114da4458bdSDavid Howells 		buflen -= segment;
115da4458bdSDavid Howells 		pos += segment;
116da4458bdSDavid Howells 	}
117da4458bdSDavid Howells 
118da4458bdSDavid Howells 	return 0;
119da4458bdSDavid Howells }
120da4458bdSDavid Howells 
121da4458bdSDavid Howells /*
122da4458bdSDavid Howells  * determine the length of a string in romfs on a block device
123da4458bdSDavid Howells  */
124da4458bdSDavid Howells static ssize_t romfs_blk_strnlen(struct super_block *sb,
125da4458bdSDavid Howells 				 unsigned long pos, size_t limit)
126da4458bdSDavid Howells {
127da4458bdSDavid Howells 	struct buffer_head *bh;
128da4458bdSDavid Howells 	unsigned long offset;
129da4458bdSDavid Howells 	ssize_t n = 0;
130da4458bdSDavid Howells 	size_t segment;
131da4458bdSDavid Howells 	u_char *buf, *p;
132da4458bdSDavid Howells 
133da4458bdSDavid Howells 	/* scan the string up to blocksize bytes at a time */
134da4458bdSDavid Howells 	while (limit > 0) {
135da4458bdSDavid Howells 		offset = pos & (ROMBSIZE - 1);
136da4458bdSDavid Howells 		segment = min_t(size_t, limit, ROMBSIZE - offset);
137da4458bdSDavid Howells 		bh = sb_bread(sb, pos >> ROMBSBITS);
138da4458bdSDavid Howells 		if (!bh)
139da4458bdSDavid Howells 			return -EIO;
140da4458bdSDavid Howells 		buf = bh->b_data + offset;
141da4458bdSDavid Howells 		p = memchr(buf, 0, segment);
142da4458bdSDavid Howells 		brelse(bh);
143da4458bdSDavid Howells 		if (p)
144da4458bdSDavid Howells 			return n + (p - buf);
145da4458bdSDavid Howells 		limit -= segment;
146da4458bdSDavid Howells 		pos += segment;
147da4458bdSDavid Howells 		n += segment;
148da4458bdSDavid Howells 	}
149da4458bdSDavid Howells 
150da4458bdSDavid Howells 	return n;
151da4458bdSDavid Howells }
152da4458bdSDavid Howells 
153da4458bdSDavid Howells /*
154da4458bdSDavid Howells  * compare a string to one in a romfs image on a block device
155da4458bdSDavid Howells  * - return 1 if matched, 0 if differ, -ve if error
156da4458bdSDavid Howells  */
157da4458bdSDavid Howells static int romfs_blk_strncmp(struct super_block *sb, unsigned long pos,
158da4458bdSDavid Howells 			     const char *str, size_t size)
159da4458bdSDavid Howells {
160da4458bdSDavid Howells 	struct buffer_head *bh;
161da4458bdSDavid Howells 	unsigned long offset;
162da4458bdSDavid Howells 	size_t segment;
163da4458bdSDavid Howells 	bool x;
164da4458bdSDavid Howells 
165da4458bdSDavid Howells 	/* scan the string up to 16 bytes at a time */
166da4458bdSDavid Howells 	while (size > 0) {
167da4458bdSDavid Howells 		offset = pos & (ROMBSIZE - 1);
168da4458bdSDavid Howells 		segment = min_t(size_t, size, ROMBSIZE - offset);
169da4458bdSDavid Howells 		bh = sb_bread(sb, pos >> ROMBSBITS);
170da4458bdSDavid Howells 		if (!bh)
171da4458bdSDavid Howells 			return -EIO;
172da4458bdSDavid Howells 		x = (memcmp(bh->b_data + offset, str, segment) != 0);
173da4458bdSDavid Howells 		brelse(bh);
174da4458bdSDavid Howells 		if (x)
175da4458bdSDavid Howells 			return 0;
176da4458bdSDavid Howells 		size -= segment;
177da4458bdSDavid Howells 		pos += segment;
178da4458bdSDavid Howells 		str += segment;
179da4458bdSDavid Howells 	}
180da4458bdSDavid Howells 
181da4458bdSDavid Howells 	return 1;
182da4458bdSDavid Howells }
183da4458bdSDavid Howells #endif /* CONFIG_ROMFS_ON_BLOCK */
184da4458bdSDavid Howells 
185da4458bdSDavid Howells /*
186da4458bdSDavid Howells  * read data from the romfs image
187da4458bdSDavid Howells  */
188da4458bdSDavid Howells int romfs_dev_read(struct super_block *sb, unsigned long pos,
189da4458bdSDavid Howells 		   void *buf, size_t buflen)
190da4458bdSDavid Howells {
191da4458bdSDavid Howells 	size_t limit;
192da4458bdSDavid Howells 
193da4458bdSDavid Howells 	limit = romfs_maxsize(sb);
194da4458bdSDavid Howells 	if (pos >= limit)
195da4458bdSDavid Howells 		return -EIO;
196da4458bdSDavid Howells 	if (buflen > limit - pos)
197da4458bdSDavid Howells 		buflen = limit - pos;
198da4458bdSDavid Howells 
199da4458bdSDavid Howells #ifdef CONFIG_ROMFS_ON_MTD
200da4458bdSDavid Howells 	if (sb->s_mtd)
201da4458bdSDavid Howells 		return romfs_mtd_read(sb, pos, buf, buflen);
202da4458bdSDavid Howells #endif
203da4458bdSDavid Howells #ifdef CONFIG_ROMFS_ON_BLOCK
204da4458bdSDavid Howells 	if (sb->s_bdev)
205da4458bdSDavid Howells 		return romfs_blk_read(sb, pos, buf, buflen);
206da4458bdSDavid Howells #endif
207da4458bdSDavid Howells 	return -EIO;
208da4458bdSDavid Howells }
209da4458bdSDavid Howells 
210da4458bdSDavid Howells /*
211da4458bdSDavid Howells  * determine the length of a string in romfs
212da4458bdSDavid Howells  */
213da4458bdSDavid Howells ssize_t romfs_dev_strnlen(struct super_block *sb,
214da4458bdSDavid Howells 			  unsigned long pos, size_t maxlen)
215da4458bdSDavid Howells {
216da4458bdSDavid Howells 	size_t limit;
217da4458bdSDavid Howells 
218da4458bdSDavid Howells 	limit = romfs_maxsize(sb);
219da4458bdSDavid Howells 	if (pos >= limit)
220da4458bdSDavid Howells 		return -EIO;
221da4458bdSDavid Howells 	if (maxlen > limit - pos)
222da4458bdSDavid Howells 		maxlen = limit - pos;
223da4458bdSDavid Howells 
224da4458bdSDavid Howells #ifdef CONFIG_ROMFS_ON_MTD
225da4458bdSDavid Howells 	if (sb->s_mtd)
226da4458bdSDavid Howells 		return romfs_mtd_strnlen(sb, pos, limit);
227da4458bdSDavid Howells #endif
228da4458bdSDavid Howells #ifdef CONFIG_ROMFS_ON_BLOCK
229da4458bdSDavid Howells 	if (sb->s_bdev)
230da4458bdSDavid Howells 		return romfs_blk_strnlen(sb, pos, limit);
231da4458bdSDavid Howells #endif
232da4458bdSDavid Howells 	return -EIO;
233da4458bdSDavid Howells }
234da4458bdSDavid Howells 
235da4458bdSDavid Howells /*
236da4458bdSDavid Howells  * compare a string to one in romfs
237da4458bdSDavid Howells  * - return 1 if matched, 0 if differ, -ve if error
238da4458bdSDavid Howells  */
239da4458bdSDavid Howells int romfs_dev_strncmp(struct super_block *sb, unsigned long pos,
240da4458bdSDavid Howells 		      const char *str, size_t size)
241da4458bdSDavid Howells {
242da4458bdSDavid Howells 	size_t limit;
243da4458bdSDavid Howells 
244da4458bdSDavid Howells 	limit = romfs_maxsize(sb);
245da4458bdSDavid Howells 	if (pos >= limit)
246da4458bdSDavid Howells 		return -EIO;
247da4458bdSDavid Howells 	if (size > ROMFS_MAXFN)
248da4458bdSDavid Howells 		return -ENAMETOOLONG;
249da4458bdSDavid Howells 	if (size > limit - pos)
250da4458bdSDavid Howells 		return -EIO;
251da4458bdSDavid Howells 
252da4458bdSDavid Howells #ifdef CONFIG_ROMFS_ON_MTD
253da4458bdSDavid Howells 	if (sb->s_mtd)
254da4458bdSDavid Howells 		return romfs_mtd_strncmp(sb, pos, str, size);
255da4458bdSDavid Howells #endif
256da4458bdSDavid Howells #ifdef CONFIG_ROMFS_ON_BLOCK
257da4458bdSDavid Howells 	if (sb->s_bdev)
258da4458bdSDavid Howells 		return romfs_blk_strncmp(sb, pos, str, size);
259da4458bdSDavid Howells #endif
260da4458bdSDavid Howells 	return -EIO;
261da4458bdSDavid Howells }
262