xref: /openbmc/linux/fs/statfs.c (revision 1fa6ac37)
1 #include <linux/syscalls.h>
2 #include <linux/module.h>
3 #include <linux/fs.h>
4 #include <linux/file.h>
5 #include <linux/namei.h>
6 #include <linux/statfs.h>
7 #include <linux/security.h>
8 #include <linux/uaccess.h>
9 
10 int vfs_statfs(struct dentry *dentry, struct kstatfs *buf)
11 {
12 	int retval = -ENODEV;
13 
14 	if (dentry) {
15 		retval = -ENOSYS;
16 		if (dentry->d_sb->s_op->statfs) {
17 			memset(buf, 0, sizeof(*buf));
18 			retval = security_sb_statfs(dentry);
19 			if (retval)
20 				return retval;
21 			retval = dentry->d_sb->s_op->statfs(dentry, buf);
22 			if (retval == 0 && buf->f_frsize == 0)
23 				buf->f_frsize = buf->f_bsize;
24 		}
25 	}
26 	return retval;
27 }
28 
29 EXPORT_SYMBOL(vfs_statfs);
30 
31 static int vfs_statfs_native(struct dentry *dentry, struct statfs *buf)
32 {
33 	struct kstatfs st;
34 	int retval;
35 
36 	retval = vfs_statfs(dentry, &st);
37 	if (retval)
38 		return retval;
39 
40 	if (sizeof(*buf) == sizeof(st))
41 		memcpy(buf, &st, sizeof(st));
42 	else {
43 		if (sizeof buf->f_blocks == 4) {
44 			if ((st.f_blocks | st.f_bfree | st.f_bavail |
45 			     st.f_bsize | st.f_frsize) &
46 			    0xffffffff00000000ULL)
47 				return -EOVERFLOW;
48 			/*
49 			 * f_files and f_ffree may be -1; it's okay to stuff
50 			 * that into 32 bits
51 			 */
52 			if (st.f_files != -1 &&
53 			    (st.f_files & 0xffffffff00000000ULL))
54 				return -EOVERFLOW;
55 			if (st.f_ffree != -1 &&
56 			    (st.f_ffree & 0xffffffff00000000ULL))
57 				return -EOVERFLOW;
58 		}
59 
60 		buf->f_type = st.f_type;
61 		buf->f_bsize = st.f_bsize;
62 		buf->f_blocks = st.f_blocks;
63 		buf->f_bfree = st.f_bfree;
64 		buf->f_bavail = st.f_bavail;
65 		buf->f_files = st.f_files;
66 		buf->f_ffree = st.f_ffree;
67 		buf->f_fsid = st.f_fsid;
68 		buf->f_namelen = st.f_namelen;
69 		buf->f_frsize = st.f_frsize;
70 		memset(buf->f_spare, 0, sizeof(buf->f_spare));
71 	}
72 	return 0;
73 }
74 
75 static int vfs_statfs64(struct dentry *dentry, struct statfs64 *buf)
76 {
77 	struct kstatfs st;
78 	int retval;
79 
80 	retval = vfs_statfs(dentry, &st);
81 	if (retval)
82 		return retval;
83 
84 	if (sizeof(*buf) == sizeof(st))
85 		memcpy(buf, &st, sizeof(st));
86 	else {
87 		buf->f_type = st.f_type;
88 		buf->f_bsize = st.f_bsize;
89 		buf->f_blocks = st.f_blocks;
90 		buf->f_bfree = st.f_bfree;
91 		buf->f_bavail = st.f_bavail;
92 		buf->f_files = st.f_files;
93 		buf->f_ffree = st.f_ffree;
94 		buf->f_fsid = st.f_fsid;
95 		buf->f_namelen = st.f_namelen;
96 		buf->f_frsize = st.f_frsize;
97 		memset(buf->f_spare, 0, sizeof(buf->f_spare));
98 	}
99 	return 0;
100 }
101 
102 SYSCALL_DEFINE2(statfs, const char __user *, pathname, struct statfs __user *, buf)
103 {
104 	struct path path;
105 	int error;
106 
107 	error = user_path(pathname, &path);
108 	if (!error) {
109 		struct statfs tmp;
110 		error = vfs_statfs_native(path.dentry, &tmp);
111 		if (!error && copy_to_user(buf, &tmp, sizeof(tmp)))
112 			error = -EFAULT;
113 		path_put(&path);
114 	}
115 	return error;
116 }
117 
118 SYSCALL_DEFINE3(statfs64, const char __user *, pathname, size_t, sz, struct statfs64 __user *, buf)
119 {
120 	struct path path;
121 	long error;
122 
123 	if (sz != sizeof(*buf))
124 		return -EINVAL;
125 	error = user_path(pathname, &path);
126 	if (!error) {
127 		struct statfs64 tmp;
128 		error = vfs_statfs64(path.dentry, &tmp);
129 		if (!error && copy_to_user(buf, &tmp, sizeof(tmp)))
130 			error = -EFAULT;
131 		path_put(&path);
132 	}
133 	return error;
134 }
135 
136 SYSCALL_DEFINE2(fstatfs, unsigned int, fd, struct statfs __user *, buf)
137 {
138 	struct file *file;
139 	struct statfs tmp;
140 	int error;
141 
142 	error = -EBADF;
143 	file = fget(fd);
144 	if (!file)
145 		goto out;
146 	error = vfs_statfs_native(file->f_path.dentry, &tmp);
147 	if (!error && copy_to_user(buf, &tmp, sizeof(tmp)))
148 		error = -EFAULT;
149 	fput(file);
150 out:
151 	return error;
152 }
153 
154 SYSCALL_DEFINE3(fstatfs64, unsigned int, fd, size_t, sz, struct statfs64 __user *, buf)
155 {
156 	struct file *file;
157 	struct statfs64 tmp;
158 	int error;
159 
160 	if (sz != sizeof(*buf))
161 		return -EINVAL;
162 
163 	error = -EBADF;
164 	file = fget(fd);
165 	if (!file)
166 		goto out;
167 	error = vfs_statfs64(file->f_path.dentry, &tmp);
168 	if (!error && copy_to_user(buf, &tmp, sizeof(tmp)))
169 		error = -EFAULT;
170 	fput(file);
171 out:
172 	return error;
173 }
174 
175 SYSCALL_DEFINE2(ustat, unsigned, dev, struct ustat __user *, ubuf)
176 {
177 	struct super_block *s;
178 	struct ustat tmp;
179 	struct kstatfs sbuf;
180 	int err;
181 
182 	s = user_get_super(new_decode_dev(dev));
183 	if (!s)
184 		return -EINVAL;
185 
186 	err = vfs_statfs(s->s_root, &sbuf);
187 	drop_super(s);
188 	if (err)
189 		return err;
190 
191 	memset(&tmp,0,sizeof(struct ustat));
192 	tmp.f_tfree = sbuf.f_bfree;
193 	tmp.f_tinode = sbuf.f_ffree;
194 
195 	return copy_to_user(ubuf, &tmp, sizeof(struct ustat)) ? -EFAULT : 0;
196 }
197