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
cstatvfs32(struct vfs * vfsp,struct statvfs32 * ubp)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
cstatvfs64(struct vfs * vfsp,struct statvfs64 * ubp)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
statvfs(char * fname,struct statvfs * sbp)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
fstatvfs(int fdes,struct statvfs * sbp)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
statvfs64(char * fname,struct statvfs64 * sbp)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
fstatvfs64(int fdes,struct statvfs64 * sbp)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
cstatvfs64_32(struct vfs * vfsp,struct statvfs64_32 * ubp)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
statvfs32(char * fname,struct statvfs32 * sbp)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
fstatvfs32(int fdes,struct statvfs32 * sbp)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
statvfs64_32(char * fname,struct statvfs64_32 * sbp)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
fstatvfs64_32(int fdes,struct statvfs64_32 * sbp)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