xref: /aosp_15_r20/external/erofs-utils/lib/diskbuf.c (revision 33b1fccf6a0fada2c2875d400ed01119b7676ee5)
1*33b1fccfSAndroid Build Coastguard Worker // SPDX-License-Identifier: GPL-2.0+ OR Apache-2.0
2*33b1fccfSAndroid Build Coastguard Worker #include "erofs/diskbuf.h"
3*33b1fccfSAndroid Build Coastguard Worker #include "erofs/internal.h"
4*33b1fccfSAndroid Build Coastguard Worker #include "erofs/print.h"
5*33b1fccfSAndroid Build Coastguard Worker #include <stdio.h>
6*33b1fccfSAndroid Build Coastguard Worker #include <errno.h>
7*33b1fccfSAndroid Build Coastguard Worker #include <sys/stat.h>
8*33b1fccfSAndroid Build Coastguard Worker #include <unistd.h>
9*33b1fccfSAndroid Build Coastguard Worker #include <stdlib.h>
10*33b1fccfSAndroid Build Coastguard Worker 
11*33b1fccfSAndroid Build Coastguard Worker /* A simple approach to avoid creating too many temporary files */
12*33b1fccfSAndroid Build Coastguard Worker static struct erofs_diskbufstrm {
13*33b1fccfSAndroid Build Coastguard Worker 	erofs_atomic_t count;
14*33b1fccfSAndroid Build Coastguard Worker 	u64 tailoffset, devpos;
15*33b1fccfSAndroid Build Coastguard Worker 	int fd;
16*33b1fccfSAndroid Build Coastguard Worker 	unsigned int alignsize;
17*33b1fccfSAndroid Build Coastguard Worker 	bool locked;
18*33b1fccfSAndroid Build Coastguard Worker } *dbufstrm;
19*33b1fccfSAndroid Build Coastguard Worker 
erofs_diskbuf_getfd(struct erofs_diskbuf * db,u64 * fpos)20*33b1fccfSAndroid Build Coastguard Worker int erofs_diskbuf_getfd(struct erofs_diskbuf *db, u64 *fpos)
21*33b1fccfSAndroid Build Coastguard Worker {
22*33b1fccfSAndroid Build Coastguard Worker 	const struct erofs_diskbufstrm *strm = db->sp;
23*33b1fccfSAndroid Build Coastguard Worker 	u64 offset;
24*33b1fccfSAndroid Build Coastguard Worker 
25*33b1fccfSAndroid Build Coastguard Worker 	if (!strm)
26*33b1fccfSAndroid Build Coastguard Worker 		return -1;
27*33b1fccfSAndroid Build Coastguard Worker 	offset = db->offset + strm->devpos;
28*33b1fccfSAndroid Build Coastguard Worker 	if (fpos)
29*33b1fccfSAndroid Build Coastguard Worker 		*fpos = offset;
30*33b1fccfSAndroid Build Coastguard Worker 	return strm->fd;
31*33b1fccfSAndroid Build Coastguard Worker }
32*33b1fccfSAndroid Build Coastguard Worker 
erofs_diskbuf_reserve(struct erofs_diskbuf * db,int sid,u64 * off)33*33b1fccfSAndroid Build Coastguard Worker int erofs_diskbuf_reserve(struct erofs_diskbuf *db, int sid, u64 *off)
34*33b1fccfSAndroid Build Coastguard Worker {
35*33b1fccfSAndroid Build Coastguard Worker 	struct erofs_diskbufstrm *strm = dbufstrm + sid;
36*33b1fccfSAndroid Build Coastguard Worker 
37*33b1fccfSAndroid Build Coastguard Worker 	if (strm->tailoffset & (strm->alignsize - 1)) {
38*33b1fccfSAndroid Build Coastguard Worker 		strm->tailoffset = round_up(strm->tailoffset, strm->alignsize);
39*33b1fccfSAndroid Build Coastguard Worker 		if (lseek(strm->fd, strm->tailoffset + strm->devpos,
40*33b1fccfSAndroid Build Coastguard Worker 			  SEEK_SET) != strm->tailoffset + strm->devpos)
41*33b1fccfSAndroid Build Coastguard Worker 			return -EIO;
42*33b1fccfSAndroid Build Coastguard Worker 	}
43*33b1fccfSAndroid Build Coastguard Worker 	db->offset = strm->tailoffset;
44*33b1fccfSAndroid Build Coastguard Worker 	if (off)
45*33b1fccfSAndroid Build Coastguard Worker 		*off = db->offset + strm->devpos;
46*33b1fccfSAndroid Build Coastguard Worker 	db->sp = strm;
47*33b1fccfSAndroid Build Coastguard Worker 	(void)erofs_atomic_inc_return(&strm->count);
48*33b1fccfSAndroid Build Coastguard Worker 	strm->locked = true;	/* TODO: need a real lock for MT */
49*33b1fccfSAndroid Build Coastguard Worker 	return strm->fd;
50*33b1fccfSAndroid Build Coastguard Worker }
51*33b1fccfSAndroid Build Coastguard Worker 
erofs_diskbuf_commit(struct erofs_diskbuf * db,u64 len)52*33b1fccfSAndroid Build Coastguard Worker void erofs_diskbuf_commit(struct erofs_diskbuf *db, u64 len)
53*33b1fccfSAndroid Build Coastguard Worker {
54*33b1fccfSAndroid Build Coastguard Worker 	struct erofs_diskbufstrm *strm = db->sp;
55*33b1fccfSAndroid Build Coastguard Worker 
56*33b1fccfSAndroid Build Coastguard Worker 	DBG_BUGON(!strm);
57*33b1fccfSAndroid Build Coastguard Worker 	DBG_BUGON(!strm->locked);
58*33b1fccfSAndroid Build Coastguard Worker 	DBG_BUGON(strm->tailoffset != db->offset);
59*33b1fccfSAndroid Build Coastguard Worker 	strm->tailoffset += len;
60*33b1fccfSAndroid Build Coastguard Worker }
61*33b1fccfSAndroid Build Coastguard Worker 
erofs_diskbuf_close(struct erofs_diskbuf * db)62*33b1fccfSAndroid Build Coastguard Worker void erofs_diskbuf_close(struct erofs_diskbuf *db)
63*33b1fccfSAndroid Build Coastguard Worker {
64*33b1fccfSAndroid Build Coastguard Worker 	struct erofs_diskbufstrm *strm = db->sp;
65*33b1fccfSAndroid Build Coastguard Worker 
66*33b1fccfSAndroid Build Coastguard Worker 	DBG_BUGON(!strm);
67*33b1fccfSAndroid Build Coastguard Worker 	DBG_BUGON(erofs_atomic_read(&strm->count) <= 1);
68*33b1fccfSAndroid Build Coastguard Worker 	(void)erofs_atomic_dec_return(&strm->count);
69*33b1fccfSAndroid Build Coastguard Worker 	db->sp = NULL;
70*33b1fccfSAndroid Build Coastguard Worker }
71*33b1fccfSAndroid Build Coastguard Worker 
erofs_tmpfile(void)72*33b1fccfSAndroid Build Coastguard Worker int erofs_tmpfile(void)
73*33b1fccfSAndroid Build Coastguard Worker {
74*33b1fccfSAndroid Build Coastguard Worker #define	TRAILER		"tmp.XXXXXXXXXX"
75*33b1fccfSAndroid Build Coastguard Worker 	char buf[PATH_MAX];
76*33b1fccfSAndroid Build Coastguard Worker 	int fd;
77*33b1fccfSAndroid Build Coastguard Worker 	umode_t u;
78*33b1fccfSAndroid Build Coastguard Worker 
79*33b1fccfSAndroid Build Coastguard Worker 	(void)snprintf(buf, sizeof(buf), "%s/" TRAILER,
80*33b1fccfSAndroid Build Coastguard Worker 		       getenv("TMPDIR") ?: "/tmp");
81*33b1fccfSAndroid Build Coastguard Worker 
82*33b1fccfSAndroid Build Coastguard Worker 	fd = mkstemp(buf);
83*33b1fccfSAndroid Build Coastguard Worker 	if (fd < 0)
84*33b1fccfSAndroid Build Coastguard Worker 		return -errno;
85*33b1fccfSAndroid Build Coastguard Worker 
86*33b1fccfSAndroid Build Coastguard Worker 	unlink(buf);
87*33b1fccfSAndroid Build Coastguard Worker 	u = umask(0);
88*33b1fccfSAndroid Build Coastguard Worker 	(void)umask(u);
89*33b1fccfSAndroid Build Coastguard Worker 	(void)fchmod(fd, 0666 & ~u);
90*33b1fccfSAndroid Build Coastguard Worker 	return fd;
91*33b1fccfSAndroid Build Coastguard Worker }
92*33b1fccfSAndroid Build Coastguard Worker 
erofs_diskbuf_init(unsigned int nstrms)93*33b1fccfSAndroid Build Coastguard Worker int erofs_diskbuf_init(unsigned int nstrms)
94*33b1fccfSAndroid Build Coastguard Worker {
95*33b1fccfSAndroid Build Coastguard Worker 	struct erofs_diskbufstrm *strm;
96*33b1fccfSAndroid Build Coastguard Worker 
97*33b1fccfSAndroid Build Coastguard Worker 	strm = calloc(nstrms + 1, sizeof(*strm));
98*33b1fccfSAndroid Build Coastguard Worker 	if (!strm)
99*33b1fccfSAndroid Build Coastguard Worker 		return -ENOMEM;
100*33b1fccfSAndroid Build Coastguard Worker 	strm[nstrms].fd = -1;
101*33b1fccfSAndroid Build Coastguard Worker 	dbufstrm = strm;
102*33b1fccfSAndroid Build Coastguard Worker 
103*33b1fccfSAndroid Build Coastguard Worker 	for (; strm < dbufstrm + nstrms; ++strm) {
104*33b1fccfSAndroid Build Coastguard Worker 		struct stat st;
105*33b1fccfSAndroid Build Coastguard Worker 
106*33b1fccfSAndroid Build Coastguard Worker 		/* try to use the devfd for regfiles on stream 0 */
107*33b1fccfSAndroid Build Coastguard Worker 		if (strm == dbufstrm && !g_sbi.bdev.ops) {
108*33b1fccfSAndroid Build Coastguard Worker 			strm->devpos = 1ULL << 40;
109*33b1fccfSAndroid Build Coastguard Worker 			if (!ftruncate(g_sbi.bdev.fd, strm->devpos << 1)) {
110*33b1fccfSAndroid Build Coastguard Worker 				strm->fd = dup(g_sbi.bdev.fd);
111*33b1fccfSAndroid Build Coastguard Worker 				if (lseek(strm->fd, strm->devpos,
112*33b1fccfSAndroid Build Coastguard Worker 					  SEEK_SET) != strm->devpos)
113*33b1fccfSAndroid Build Coastguard Worker 					return -EIO;
114*33b1fccfSAndroid Build Coastguard Worker 				goto setupone;
115*33b1fccfSAndroid Build Coastguard Worker 			}
116*33b1fccfSAndroid Build Coastguard Worker 		}
117*33b1fccfSAndroid Build Coastguard Worker 		strm->devpos = 0;
118*33b1fccfSAndroid Build Coastguard Worker 		strm->fd = erofs_tmpfile();
119*33b1fccfSAndroid Build Coastguard Worker 		if (strm->fd < 0)
120*33b1fccfSAndroid Build Coastguard Worker 			return -ENOSPC;
121*33b1fccfSAndroid Build Coastguard Worker setupone:
122*33b1fccfSAndroid Build Coastguard Worker 		strm->tailoffset = 0;
123*33b1fccfSAndroid Build Coastguard Worker 		erofs_atomic_set(&strm->count, 1);
124*33b1fccfSAndroid Build Coastguard Worker 		if (fstat(strm->fd, &st))
125*33b1fccfSAndroid Build Coastguard Worker 			return -errno;
126*33b1fccfSAndroid Build Coastguard Worker 		strm->alignsize = max_t(u32, st.st_blksize, getpagesize());
127*33b1fccfSAndroid Build Coastguard Worker 	}
128*33b1fccfSAndroid Build Coastguard Worker 	return 0;
129*33b1fccfSAndroid Build Coastguard Worker }
130*33b1fccfSAndroid Build Coastguard Worker 
erofs_diskbuf_exit(void)131*33b1fccfSAndroid Build Coastguard Worker void erofs_diskbuf_exit(void)
132*33b1fccfSAndroid Build Coastguard Worker {
133*33b1fccfSAndroid Build Coastguard Worker 	struct erofs_diskbufstrm *strm;
134*33b1fccfSAndroid Build Coastguard Worker 
135*33b1fccfSAndroid Build Coastguard Worker 	if (!dbufstrm)
136*33b1fccfSAndroid Build Coastguard Worker 		return;
137*33b1fccfSAndroid Build Coastguard Worker 
138*33b1fccfSAndroid Build Coastguard Worker 	for (strm = dbufstrm; strm->fd >= 0; ++strm) {
139*33b1fccfSAndroid Build Coastguard Worker 		DBG_BUGON(erofs_atomic_read(&strm->count) != 1);
140*33b1fccfSAndroid Build Coastguard Worker 
141*33b1fccfSAndroid Build Coastguard Worker 		close(strm->fd);
142*33b1fccfSAndroid Build Coastguard Worker 		strm->fd = -1;
143*33b1fccfSAndroid Build Coastguard Worker 	}
144*33b1fccfSAndroid Build Coastguard Worker }
145