xref: /freebsd/lib/libufs/block.c (revision 4f52dfbb8d6c4d446500c5b097e3806ec219fbd4)
1 /*-
2  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3  *
4  * Copyright (c) 2002 Juli Mallett.  All rights reserved.
5  *
6  * This software was written by Juli Mallett <jmallett@FreeBSD.org> for the
7  * FreeBSD project.  Redistribution and use in source and binary forms, with
8  * or without modification, are permitted provided that the following
9  * conditions are met:
10  *
11  * 1. Redistribution of source code must retain the above copyright notice,
12  *    this list of conditions and the following disclaimer.
13  * 2. Redistribution in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
19  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
20  * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
21  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
22  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
23  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
25  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
26  * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27  * POSSIBILITY OF SUCH DAMAGE.
28  */
29 
30 #include <sys/cdefs.h>
31 __FBSDID("$FreeBSD$");
32 
33 #include <sys/param.h>
34 #include <sys/mount.h>
35 #include <sys/disk.h>
36 #include <sys/disklabel.h>
37 #include <sys/stat.h>
38 
39 #include <ufs/ufs/ufsmount.h>
40 #include <ufs/ufs/dinode.h>
41 #include <ufs/ffs/fs.h>
42 
43 #include <errno.h>
44 #include <fcntl.h>
45 #include <stdio.h>
46 #include <stdlib.h>
47 #include <string.h>
48 #include <unistd.h>
49 
50 #include <libufs.h>
51 
52 ssize_t
53 bread(struct uufsd *disk, ufs2_daddr_t blockno, void *data, size_t size)
54 {
55 	void *p2;
56 	ssize_t cnt;
57 
58 	ERROR(disk, NULL);
59 
60 	p2 = data;
61 	/*
62 	 * XXX: various disk controllers require alignment of our buffer
63 	 * XXX: which is stricter than struct alignment.
64 	 * XXX: Bounce the buffer if not 64 byte aligned.
65 	 * XXX: this can be removed if/when the kernel is fixed
66 	 */
67 	if (((intptr_t)data) & 0x3f) {
68 		p2 = malloc(size);
69 		if (p2 == NULL) {
70 			ERROR(disk, "allocate bounce buffer");
71 			goto fail;
72 		}
73 	}
74 	cnt = pread(disk->d_fd, p2, size, (off_t)(blockno * disk->d_bsize));
75 	if (cnt == -1) {
76 		ERROR(disk, "read error from block device");
77 		goto fail;
78 	}
79 	if (cnt == 0) {
80 		ERROR(disk, "end of file from block device");
81 		goto fail;
82 	}
83 	if ((size_t)cnt != size) {
84 		ERROR(disk, "short read or read error from block device");
85 		goto fail;
86 	}
87 	if (p2 != data) {
88 		memcpy(data, p2, size);
89 		free(p2);
90 	}
91 	return (cnt);
92 fail:	memset(data, 0, size);
93 	if (p2 != data) {
94 		free(p2);
95 	}
96 	return (-1);
97 }
98 
99 ssize_t
100 bwrite(struct uufsd *disk, ufs2_daddr_t blockno, const void *data, size_t size)
101 {
102 	ssize_t cnt;
103 	int rv;
104 	void *p2 = NULL;
105 
106 	ERROR(disk, NULL);
107 
108 	rv = ufs_disk_write(disk);
109 	if (rv == -1) {
110 		ERROR(disk, "failed to open disk for writing");
111 		return (-1);
112 	}
113 
114 	/*
115 	 * XXX: various disk controllers require alignment of our buffer
116 	 * XXX: which is stricter than struct alignment.
117 	 * XXX: Bounce the buffer if not 64 byte aligned.
118 	 * XXX: this can be removed if/when the kernel is fixed
119 	 */
120 	if (((intptr_t)data) & 0x3f) {
121 		p2 = malloc(size);
122 		if (p2 == NULL) {
123 			ERROR(disk, "allocate bounce buffer");
124 			return (-1);
125 		}
126 		memcpy(p2, data, size);
127 		data = p2;
128 	}
129 	cnt = pwrite(disk->d_fd, data, size, (off_t)(blockno * disk->d_bsize));
130 	if (p2 != NULL)
131 		free(p2);
132 	if (cnt == -1) {
133 		ERROR(disk, "write error to block device");
134 		return (-1);
135 	}
136 	if ((size_t)cnt != size) {
137 		ERROR(disk, "short write to block device");
138 		return (-1);
139 	}
140 
141 	return (cnt);
142 }
143 
144 #ifdef __FreeBSD_kernel__
145 
146 static int
147 berase_helper(struct uufsd *disk, ufs2_daddr_t blockno, ufs2_daddr_t size)
148 {
149 	off_t ioarg[2];
150 
151 	ioarg[0] = blockno * disk->d_bsize;
152 	ioarg[1] = size;
153 	return (ioctl(disk->d_fd, DIOCGDELETE, ioarg));
154 }
155 
156 #else
157 
158 static int
159 berase_helper(struct uufsd *disk, ufs2_daddr_t blockno, ufs2_daddr_t size)
160 {
161 	char *zero_chunk;
162 	off_t offset, zero_chunk_size, pwrite_size;
163 	int rv;
164 
165 	offset = blockno * disk->d_bsize;
166 	zero_chunk_size = 65536 * disk->d_bsize;
167 	zero_chunk = calloc(1, zero_chunk_size);
168 	if (zero_chunk == NULL) {
169 		ERROR(disk, "failed to allocate memory");
170 		return (-1);
171 	}
172 	while (size > 0) {
173 		pwrite_size = size;
174 		if (pwrite_size > zero_chunk_size)
175 			pwrite_size = zero_chunk_size;
176 		rv = pwrite(disk->d_fd, zero_chunk, pwrite_size, offset);
177 		if (rv == -1) {
178 			ERROR(disk, "failed writing to disk");
179 			break;
180 		}
181 		size -= rv;
182 		offset += rv;
183 		rv = 0;
184 	}
185 	free(zero_chunk);
186 	return (rv);
187 }
188 
189 #endif
190 
191 int
192 berase(struct uufsd *disk, ufs2_daddr_t blockno, ufs2_daddr_t size)
193 {
194 	int rv;
195 
196 	ERROR(disk, NULL);
197 	rv = ufs_disk_write(disk);
198 	if (rv == -1) {
199 		ERROR(disk, "failed to open disk for writing");
200 		return(rv);
201 	}
202 	return (berase_helper(disk, blockno, size));
203 }
204