xref: /illumos-gate/usr/src/uts/common/syscall/statvfs.c (revision 7a6d80f1660abd4755c68cbd094d4a914681d26e)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 /*
22  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  */
25 
26 /*	Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T	*/
27 /*	  All Rights Reserved  	*/
28 
29 /*
30  * Portions of this source code were derived from Berkeley 4.3 BSD
31  * under license from the Regents of the University of California.
32  */
33 
34 /*
35  * Get file system statistics (statvfs and fstatvfs).
36  */
37 
38 #include <sys/types.h>
39 #include <sys/inttypes.h>
40 #include <sys/t_lock.h>
41 #include <sys/param.h>
42 #include <sys/errno.h>
43 #include <sys/fstyp.h>
44 #include <sys/systm.h>
45 #include <sys/vfs.h>
46 #include <sys/statvfs.h>
47 #include <sys/vnode.h>
48 #include <sys/file.h>
49 #include <sys/cmn_err.h>
50 #include <sys/debug.h>
51 #include <sys/pathname.h>
52 
53 #include <vm/page.h>
54 #include <fs/fs_subr.h>
55 
56 #define	STATVFSCOPY(dst, src)					\
57 	(dst)->f_bsize	= (src)->f_bsize;			\
58 	(dst)->f_frsize	= (src)->f_frsize;			\
59 	(dst)->f_blocks	= (src)->f_blocks;			\
60 	(dst)->f_bfree	= (src)->f_bfree;			\
61 	(dst)->f_bavail	= (src)->f_bavail;			\
62 	(dst)->f_files	= (src)->f_files;			\
63 	(dst)->f_ffree	= (src)->f_ffree;			\
64 	(dst)->f_favail	= (src)->f_favail;			\
65 	(dst)->f_fsid	= (src)->f_fsid;			\
66 	bcopy((src)->f_basetype, (dst)->f_basetype,		\
67 		sizeof ((dst)->f_basetype));			\
68 	(dst)->f_flag	= (src)->f_flag;			\
69 	(dst)->f_namemax = (src)->f_namemax;			\
70 	bcopy((src)->f_fstr, (dst)->f_fstr,			\
71 		sizeof ((dst)->f_fstr))
72 
73 /*
74  * Common routines for statvfs and fstatvfs.
75  */
76 
77 static int
78 cstatvfs32(struct vfs *vfsp, struct statvfs32 *ubp)
79 {
80 	struct statvfs64 ds64;
81 	struct statvfs32 ds32;
82 	int error;
83 
84 #if !defined(lint)
85 	ASSERT32(sizeof (struct statvfs) == sizeof (struct statvfs32));
86 	ASSERT32(sizeof (struct statvfs64) == sizeof (struct statvfs64_32));
87 #endif
88 
89 	bzero(&ds64, sizeof (ds64));
90 	if ((error = VFS_STATVFS(vfsp, &ds64)) != 0)
91 		return (error);
92 
93 	/*
94 	 * VFS_STATVFS can return data that is incompatible with the space
95 	 * available the 32-bit statvfs structure.  Check here to see if
96 	 * it will fit into the 32-bit structure, if not, return EOVERFLOW.
97 	 *
98 	 * The check for -1 is because some file systems return -1 in the
99 	 * fields that are irrelevant or nonessential, and we do not want
100 	 * to return EOVERFLOW for them.  For example: df is expected to
101 	 * show -1 in the output for some of these fields on NFS mounted
102 	 * filesystems.
103 	 */
104 	if (ds64.f_files == (fsfilcnt64_t)-1)
105 		ds64.f_files = UINT32_MAX;
106 	if (ds64.f_ffree == (fsfilcnt64_t)-1)
107 		ds64.f_ffree = UINT32_MAX;
108 	if (ds64.f_favail == (fsfilcnt64_t)-1)
109 		ds64.f_favail = UINT32_MAX;
110 	if (ds64.f_bavail == (fsblkcnt64_t)-1)
111 		ds64.f_bavail = UINT32_MAX;
112 	if (ds64.f_bfree == (fsblkcnt64_t)-1)
113 		ds64.f_bfree = UINT32_MAX;
114 
115 	if (ds64.f_blocks > UINT32_MAX || ds64.f_bfree > UINT32_MAX ||
116 	    ds64.f_bavail > UINT32_MAX || ds64.f_files > UINT32_MAX ||
117 	    ds64.f_ffree > UINT32_MAX || ds64.f_favail > UINT32_MAX)
118 		return (EOVERFLOW);
119 #ifdef _LP64
120 	/*
121 	 * On the 64-bit kernel, even these fields grow to 64-bit
122 	 * quantities in the statvfs64 structure.
123 	 */
124 	if (ds64.f_namemax == (ulong_t)-1l)
125 		ds64.f_namemax = UINT32_MAX;
126 
127 	if (ds64.f_bsize > UINT32_MAX || ds64.f_frsize > UINT32_MAX ||
128 	    ds64.f_fsid > UINT32_MAX || ds64.f_flag > UINT32_MAX ||
129 	    ds64.f_namemax > UINT32_MAX)
130 		return (EOVERFLOW);
131 #endif
132 
133 	bzero(&ds32, sizeof (ds32));
134 	STATVFSCOPY(&ds32, &ds64);
135 	if (copyout(&ds32, ubp, sizeof (ds32)) != 0)
136 		return (EFAULT);
137 	return (0);
138 }
139 
140 static int
141 cstatvfs64(struct vfs *vfsp, struct statvfs64 *ubp)
142 {
143 	struct statvfs64 ds64;
144 	int error;
145 
146 #if !defined(lint)
147 	ASSERT64(sizeof (struct statvfs) == sizeof (struct statvfs64));
148 #endif
149 	bzero(&ds64, sizeof (ds64));
150 	if ((error = VFS_STATVFS(vfsp, &ds64)) != 0)
151 		return (error);
152 	if (copyout(&ds64, ubp, sizeof (ds64)) != 0)
153 		return (EFAULT);
154 	return (0);
155 }
156 
157 /*
158  * Native system calls
159  */
160 int
161 statvfs(char *fname, struct statvfs *sbp)
162 {
163 	vnode_t *vp;
164 	int error;
165 	int estale_retry = 0;
166 
167 lookup:
168 	if (error = lookupname(fname, UIO_USERSPACE, FOLLOW, NULLVPP, &vp)) {
169 		if ((error == ESTALE) && fs_need_estale_retry(estale_retry++))
170 			goto lookup;
171 		return (set_errno(error));
172 	}
173 #ifdef _LP64
174 	error = cstatvfs64(vp->v_vfsp, (struct statvfs64 *)sbp);
175 #else
176 	error = cstatvfs32(vp->v_vfsp, (struct statvfs32 *)sbp);
177 #endif
178 	VN_RELE(vp);
179 	if (error) {
180 		if ((error == ESTALE) && fs_need_estale_retry(estale_retry++))
181 			goto lookup;
182 		return (set_errno(error));
183 	}
184 	return (0);
185 }
186 
187 int
188 fstatvfs(int fdes, struct statvfs *sbp)
189 {
190 	struct file *fp;
191 	int error;
192 
193 	if ((fp = getf(fdes)) == NULL)
194 		return (set_errno(EBADF));
195 #ifdef _LP64
196 	error = cstatvfs64(fp->f_vnode->v_vfsp, (struct statvfs64 *)sbp);
197 #else
198 	error = cstatvfs32(fp->f_vnode->v_vfsp, (struct statvfs32 *)sbp);
199 #endif
200 	releasef(fdes);
201 	if (error)
202 		return (set_errno(error));
203 	return (0);
204 }
205 
206 #if defined(_ILP32)
207 
208 /*
209  * Large File system calls.
210  *
211  * (We deliberately don't have special "large file" system calls in the
212  * 64-bit kernel -- we just use the native versions, since they're just
213  * as functional.)
214  */
215 int
216 statvfs64(char *fname, struct statvfs64 *sbp)
217 {
218 	vnode_t *vp;
219 	int error;
220 	int estale_retry = 0;
221 
222 lookup:
223 	if (error = lookupname(fname, UIO_USERSPACE, FOLLOW, NULLVPP, &vp)) {
224 		if ((error == ESTALE) && fs_need_estale_retry(estale_retry++))
225 			goto lookup;
226 		return (set_errno(error));
227 	}
228 	error = cstatvfs64(vp->v_vfsp, sbp);
229 	VN_RELE(vp);
230 	if (error) {
231 		if ((error == ESTALE) && fs_need_estale_retry(estale_retry++))
232 			goto lookup;
233 		return (set_errno(error));
234 	}
235 	return (0);
236 }
237 
238 int
239 fstatvfs64(int fdes, struct statvfs64 *sbp)
240 {
241 	struct file *fp;
242 	int error;
243 
244 	if ((fp = getf(fdes)) == NULL)
245 		return (set_errno(EBADF));
246 	error = cstatvfs64(fp->f_vnode->v_vfsp, sbp);
247 	releasef(fdes);
248 	if (error)
249 		return (set_errno(error));
250 	return (0);
251 }
252 
253 #endif	/* _ILP32 */
254 
255 #ifdef _SYSCALL32_IMPL
256 
257 static int
258 cstatvfs64_32(struct vfs *vfsp, struct statvfs64_32 *ubp)
259 {
260 	struct statvfs64 ds64;
261 	struct statvfs64_32 ds64_32;
262 	int error;
263 
264 	bzero(&ds64, sizeof (ds64));
265 	if ((error = VFS_STATVFS(vfsp, &ds64)) != 0)
266 		return (error);
267 
268 	/*
269 	 * On the 64-bit kernel, even these fields grow to 64-bit
270 	 * quantities in the statvfs64 structure.
271 	 */
272 	if (ds64.f_namemax == (ulong_t)-1l)
273 		ds64.f_namemax = UINT32_MAX;
274 
275 	if (ds64.f_bsize > UINT32_MAX || ds64.f_frsize > UINT32_MAX ||
276 	    ds64.f_fsid > UINT32_MAX || ds64.f_flag > UINT32_MAX ||
277 	    ds64.f_namemax > UINT32_MAX)
278 		return (EOVERFLOW);
279 
280 	STATVFSCOPY(&ds64_32, &ds64);
281 	if (copyout(&ds64_32, ubp, sizeof (ds64_32)) != 0)
282 		return (EFAULT);
283 	return (0);
284 }
285 
286 /*
287  * ILP32 "small file" system calls on LP64 kernel
288  */
289 int
290 statvfs32(char *fname, struct statvfs32 *sbp)
291 {
292 	vnode_t *vp;
293 	int error;
294 	int estale_retry = 0;
295 
296 lookup:
297 	if (error = lookupname(fname, UIO_USERSPACE, FOLLOW, NULLVPP, &vp)) {
298 		if ((error == ESTALE) && fs_need_estale_retry(estale_retry++))
299 			goto lookup;
300 		return (set_errno(error));
301 	}
302 	error = cstatvfs32(vp->v_vfsp, sbp);
303 	VN_RELE(vp);
304 	if (error) {
305 		if ((error == ESTALE) && fs_need_estale_retry(estale_retry++))
306 			goto lookup;
307 		return (set_errno(error));
308 	}
309 	return (0);
310 }
311 
312 int
313 fstatvfs32(int fdes, struct statvfs32 *sbp)
314 {
315 	struct file *fp;
316 	int error;
317 
318 	if ((fp = getf(fdes)) == NULL)
319 		return (set_errno(EBADF));
320 	error = cstatvfs32(fp->f_vnode->v_vfsp, sbp);
321 	releasef(fdes);
322 	if (error)
323 		return (set_errno(error));
324 	return (0);
325 }
326 
327 /*
328  * ILP32 Large File system calls on LP64 kernel
329  */
330 int
331 statvfs64_32(char *fname, struct statvfs64_32 *sbp)
332 {
333 	vnode_t *vp;
334 	int error;
335 	int estale_retry = 0;
336 
337 lookup:
338 	if (error = lookupname(fname, UIO_USERSPACE, FOLLOW, NULLVPP, &vp)) {
339 		if ((error == ESTALE) && fs_need_estale_retry(estale_retry++))
340 			goto lookup;
341 		return (set_errno(error));
342 	}
343 	error = cstatvfs64_32(vp->v_vfsp, sbp);
344 	VN_RELE(vp);
345 	if (error) {
346 		if ((error == ESTALE) && fs_need_estale_retry(estale_retry++))
347 			goto lookup;
348 		return (set_errno(error));
349 	}
350 	return (0);
351 }
352 
353 int
354 fstatvfs64_32(int fdes, struct statvfs64_32 *sbp)
355 {
356 	struct file *fp;
357 	int error;
358 
359 	if ((fp = getf(fdes)) == NULL)
360 		return (set_errno(EBADF));
361 	error = cstatvfs64_32(fp->f_vnode->v_vfsp, sbp);
362 	releasef(fdes);
363 	if (error)
364 		return (set_errno(error));
365 	return (0);
366 }
367 
368 #endif	/* _SYSCALL32_IMPL */
369