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 #pragma ident "%Z%%M% %I% %E% SMI"
35
36 /*
37 * Get file system statistics (statvfs and fstatvfs).
38 */
39
40 #include <sys/types.h>
41 #include <sys/inttypes.h>
42 #include <sys/t_lock.h>
43 #include <sys/param.h>
44 #include <sys/errno.h>
45 #include <sys/fstyp.h>
46 #include <sys/systm.h>
47 #include <sys/vfs.h>
48 #include <sys/statvfs.h>
49 #include <sys/vnode.h>
50 #include <sys/file.h>
51 #include <sys/cmn_err.h>
52 #include <sys/debug.h>
53 #include <sys/pathname.h>
54
55 #include <vm/page.h>
56 #include <fs/fs_subr.h>
57
58 #define STATVFSCOPY(dst, src) \
59 (dst)->f_bsize = (src)->f_bsize; \
60 (dst)->f_frsize = (src)->f_frsize; \
61 (dst)->f_blocks = (src)->f_blocks; \
62 (dst)->f_bfree = (src)->f_bfree; \
63 (dst)->f_bavail = (src)->f_bavail; \
64 (dst)->f_files = (src)->f_files; \
65 (dst)->f_ffree = (src)->f_ffree; \
66 (dst)->f_favail = (src)->f_favail; \
67 (dst)->f_fsid = (src)->f_fsid; \
68 bcopy((src)->f_basetype, (dst)->f_basetype, \
69 sizeof ((dst)->f_basetype)); \
70 (dst)->f_flag = (src)->f_flag; \
71 (dst)->f_namemax = (src)->f_namemax; \
72 bcopy((src)->f_fstr, (dst)->f_fstr, \
73 sizeof ((dst)->f_fstr))
74
75 /*
76 * Common routines for statvfs and fstatvfs.
77 */
78
79 static int
cstatvfs32(struct vfs * vfsp,struct statvfs32 * ubp)80 cstatvfs32(struct vfs *vfsp, struct statvfs32 *ubp)
81 {
82 struct statvfs64 ds64;
83 struct statvfs32 ds32;
84 int error;
85
86 #if !defined(lint)
87 ASSERT32(sizeof (struct statvfs) == sizeof (struct statvfs32));
88 ASSERT32(sizeof (struct statvfs64) == sizeof (struct statvfs64_32));
89 #endif
90
91 bzero(&ds64, sizeof (ds64));
92 if ((error = VFS_STATVFS(vfsp, &ds64)) != 0)
93 return (error);
94
95 /*
96 * VFS_STATVFS can return data that is incompatible with the space
97 * available the 32-bit statvfs structure. Check here to see if
98 * it will fit into the 32-bit structure, if not, return EOVERFLOW.
99 *
100 * The check for -1 is because some file systems return -1 in the
101 * fields that are irrelevant or nonessential, and we do not want
102 * to return EOVERFLOW for them. For example: df is expected to
103 * show -1 in the output for some of these fields on NFS mounted
104 * filesystems.
105 */
106 if (ds64.f_files == (fsfilcnt64_t)-1)
107 ds64.f_files = UINT32_MAX;
108 if (ds64.f_ffree == (fsfilcnt64_t)-1)
109 ds64.f_ffree = UINT32_MAX;
110 if (ds64.f_favail == (fsfilcnt64_t)-1)
111 ds64.f_favail = UINT32_MAX;
112 if (ds64.f_bavail == (fsblkcnt64_t)-1)
113 ds64.f_bavail = UINT32_MAX;
114 if (ds64.f_bfree == (fsblkcnt64_t)-1)
115 ds64.f_bfree = UINT32_MAX;
116
117 if (ds64.f_blocks > UINT32_MAX || ds64.f_bfree > UINT32_MAX ||
118 ds64.f_bavail > UINT32_MAX || ds64.f_files > UINT32_MAX ||
119 ds64.f_ffree > UINT32_MAX || ds64.f_favail > UINT32_MAX)
120 return (EOVERFLOW);
121 #ifdef _LP64
122 /*
123 * On the 64-bit kernel, even these fields grow to 64-bit
124 * quantities in the statvfs64 structure.
125 */
126 if (ds64.f_namemax == (ulong_t)-1l)
127 ds64.f_namemax = UINT32_MAX;
128
129 if (ds64.f_bsize > UINT32_MAX || ds64.f_frsize > UINT32_MAX ||
130 ds64.f_fsid > UINT32_MAX || ds64.f_flag > UINT32_MAX ||
131 ds64.f_namemax > UINT32_MAX)
132 return (EOVERFLOW);
133 #endif
134
135 bzero(&ds32, sizeof (ds32));
136 STATVFSCOPY(&ds32, &ds64);
137 if (copyout(&ds32, ubp, sizeof (ds32)) != 0)
138 return (EFAULT);
139 return (0);
140 }
141
142 static int
cstatvfs64(struct vfs * vfsp,struct statvfs64 * ubp)143 cstatvfs64(struct vfs *vfsp, struct statvfs64 *ubp)
144 {
145 struct statvfs64 ds64;
146 int error;
147
148 #if !defined(lint)
149 ASSERT64(sizeof (struct statvfs) == sizeof (struct statvfs64));
150 #endif
151 bzero(&ds64, sizeof (ds64));
152 if ((error = VFS_STATVFS(vfsp, &ds64)) != 0)
153 return (error);
154 if (copyout(&ds64, ubp, sizeof (ds64)) != 0)
155 return (EFAULT);
156 return (0);
157 }
158
159 /*
160 * Native system calls
161 */
162 int
statvfs(char * fname,struct statvfs * sbp)163 statvfs(char *fname, struct statvfs *sbp)
164 {
165 vnode_t *vp;
166 int error;
167 int estale_retry = 0;
168
169 lookup:
170 if (error = lookupname(fname, UIO_USERSPACE, FOLLOW, NULLVPP, &vp)) {
171 if ((error == ESTALE) && fs_need_estale_retry(estale_retry++))
172 goto lookup;
173 return (set_errno(error));
174 }
175 #ifdef _LP64
176 error = cstatvfs64(vp->v_vfsp, (struct statvfs64 *)sbp);
177 #else
178 error = cstatvfs32(vp->v_vfsp, (struct statvfs32 *)sbp);
179 #endif
180 VN_RELE(vp);
181 if (error) {
182 if ((error == ESTALE) && fs_need_estale_retry(estale_retry++))
183 goto lookup;
184 return (set_errno(error));
185 }
186 return (0);
187 }
188
189 int
fstatvfs(int fdes,struct statvfs * sbp)190 fstatvfs(int fdes, struct statvfs *sbp)
191 {
192 struct file *fp;
193 int error;
194
195 if ((fp = getf(fdes)) == NULL)
196 return (set_errno(EBADF));
197 #ifdef _LP64
198 error = cstatvfs64(fp->f_vnode->v_vfsp, (struct statvfs64 *)sbp);
199 #else
200 error = cstatvfs32(fp->f_vnode->v_vfsp, (struct statvfs32 *)sbp);
201 #endif
202 releasef(fdes);
203 if (error)
204 return (set_errno(error));
205 return (0);
206 }
207
208 #if defined(_ILP32)
209
210 /*
211 * Large File system calls.
212 *
213 * (We deliberately don't have special "large file" system calls in the
214 * 64-bit kernel -- we just use the native versions, since they're just
215 * as functional.)
216 */
217 int
statvfs64(char * fname,struct statvfs64 * sbp)218 statvfs64(char *fname, struct statvfs64 *sbp)
219 {
220 vnode_t *vp;
221 int error;
222 int estale_retry = 0;
223
224 lookup:
225 if (error = lookupname(fname, UIO_USERSPACE, FOLLOW, NULLVPP, &vp)) {
226 if ((error == ESTALE) && fs_need_estale_retry(estale_retry++))
227 goto lookup;
228 return (set_errno(error));
229 }
230 error = cstatvfs64(vp->v_vfsp, sbp);
231 VN_RELE(vp);
232 if (error) {
233 if ((error == ESTALE) && fs_need_estale_retry(estale_retry++))
234 goto lookup;
235 return (set_errno(error));
236 }
237 return (0);
238 }
239
240 int
fstatvfs64(int fdes,struct statvfs64 * sbp)241 fstatvfs64(int fdes, struct statvfs64 *sbp)
242 {
243 struct file *fp;
244 int error;
245
246 if ((fp = getf(fdes)) == NULL)
247 return (set_errno(EBADF));
248 error = cstatvfs64(fp->f_vnode->v_vfsp, sbp);
249 releasef(fdes);
250 if (error)
251 return (set_errno(error));
252 return (0);
253 }
254
255 #endif /* _ILP32 */
256
257 #ifdef _SYSCALL32_IMPL
258
259 static int
cstatvfs64_32(struct vfs * vfsp,struct statvfs64_32 * ubp)260 cstatvfs64_32(struct vfs *vfsp, struct statvfs64_32 *ubp)
261 {
262 struct statvfs64 ds64;
263 struct statvfs64_32 ds64_32;
264 int error;
265
266 bzero(&ds64, sizeof (ds64));
267 if ((error = VFS_STATVFS(vfsp, &ds64)) != 0)
268 return (error);
269
270 /*
271 * On the 64-bit kernel, even these fields grow to 64-bit
272 * quantities in the statvfs64 structure.
273 */
274 if (ds64.f_namemax == (ulong_t)-1l)
275 ds64.f_namemax = UINT32_MAX;
276
277 if (ds64.f_bsize > UINT32_MAX || ds64.f_frsize > UINT32_MAX ||
278 ds64.f_fsid > UINT32_MAX || ds64.f_flag > UINT32_MAX ||
279 ds64.f_namemax > UINT32_MAX)
280 return (EOVERFLOW);
281
282 STATVFSCOPY(&ds64_32, &ds64);
283 if (copyout(&ds64_32, ubp, sizeof (ds64_32)) != 0)
284 return (EFAULT);
285 return (0);
286 }
287
288 /*
289 * ILP32 "small file" system calls on LP64 kernel
290 */
291 int
statvfs32(char * fname,struct statvfs32 * sbp)292 statvfs32(char *fname, struct statvfs32 *sbp)
293 {
294 vnode_t *vp;
295 int error;
296 int estale_retry = 0;
297
298 lookup:
299 if (error = lookupname(fname, UIO_USERSPACE, FOLLOW, NULLVPP, &vp)) {
300 if ((error == ESTALE) && fs_need_estale_retry(estale_retry++))
301 goto lookup;
302 return (set_errno(error));
303 }
304 error = cstatvfs32(vp->v_vfsp, sbp);
305 VN_RELE(vp);
306 if (error) {
307 if ((error == ESTALE) && fs_need_estale_retry(estale_retry++))
308 goto lookup;
309 return (set_errno(error));
310 }
311 return (0);
312 }
313
314 int
fstatvfs32(int fdes,struct statvfs32 * sbp)315 fstatvfs32(int fdes, struct statvfs32 *sbp)
316 {
317 struct file *fp;
318 int error;
319
320 if ((fp = getf(fdes)) == NULL)
321 return (set_errno(EBADF));
322 error = cstatvfs32(fp->f_vnode->v_vfsp, sbp);
323 releasef(fdes);
324 if (error)
325 return (set_errno(error));
326 return (0);
327 }
328
329 /*
330 * ILP32 Large File system calls on LP64 kernel
331 */
332 int
statvfs64_32(char * fname,struct statvfs64_32 * sbp)333 statvfs64_32(char *fname, struct statvfs64_32 *sbp)
334 {
335 vnode_t *vp;
336 int error;
337 int estale_retry = 0;
338
339 lookup:
340 if (error = lookupname(fname, UIO_USERSPACE, FOLLOW, NULLVPP, &vp)) {
341 if ((error == ESTALE) && fs_need_estale_retry(estale_retry++))
342 goto lookup;
343 return (set_errno(error));
344 }
345 error = cstatvfs64_32(vp->v_vfsp, sbp);
346 VN_RELE(vp);
347 if (error) {
348 if ((error == ESTALE) && fs_need_estale_retry(estale_retry++))
349 goto lookup;
350 return (set_errno(error));
351 }
352 return (0);
353 }
354
355 int
fstatvfs64_32(int fdes,struct statvfs64_32 * sbp)356 fstatvfs64_32(int fdes, struct statvfs64_32 *sbp)
357 {
358 struct file *fp;
359 int error;
360
361 if ((fp = getf(fdes)) == NULL)
362 return (set_errno(EBADF));
363 error = cstatvfs64_32(fp->f_vnode->v_vfsp, sbp);
364 releasef(fdes);
365 if (error)
366 return (set_errno(error));
367 return (0);
368 }
369
370 #endif /* _SYSCALL32_IMPL */
371