linux/fs/statfs.c
<<
>>
Prefs
   1#include <linux/syscalls.h>
   2#include <linux/export.h>
   3#include <linux/fs.h>
   4#include <linux/file.h>
   5#include <linux/mount.h>
   6#include <linux/namei.h>
   7#include <linux/statfs.h>
   8#include <linux/security.h>
   9#include <linux/uaccess.h>
  10#include <linux/compat.h>
  11#include "internal.h"
  12
  13static int flags_by_mnt(int mnt_flags)
  14{
  15        int flags = 0;
  16
  17        if (mnt_flags & MNT_READONLY)
  18                flags |= ST_RDONLY;
  19        if (mnt_flags & MNT_NOSUID)
  20                flags |= ST_NOSUID;
  21        if (mnt_flags & MNT_NODEV)
  22                flags |= ST_NODEV;
  23        if (mnt_flags & MNT_NOEXEC)
  24                flags |= ST_NOEXEC;
  25        if (mnt_flags & MNT_NOATIME)
  26                flags |= ST_NOATIME;
  27        if (mnt_flags & MNT_NODIRATIME)
  28                flags |= ST_NODIRATIME;
  29        if (mnt_flags & MNT_RELATIME)
  30                flags |= ST_RELATIME;
  31        return flags;
  32}
  33
  34static int flags_by_sb(int s_flags)
  35{
  36        int flags = 0;
  37        if (s_flags & MS_SYNCHRONOUS)
  38                flags |= ST_SYNCHRONOUS;
  39        if (s_flags & MS_MANDLOCK)
  40                flags |= ST_MANDLOCK;
  41        if (s_flags & MS_RDONLY)
  42                flags |= ST_RDONLY;
  43        return flags;
  44}
  45
  46static int calculate_f_flags(struct vfsmount *mnt)
  47{
  48        return ST_VALID | flags_by_mnt(mnt->mnt_flags) |
  49                flags_by_sb(mnt->mnt_sb->s_flags);
  50}
  51
  52static int statfs_by_dentry(struct dentry *dentry, struct kstatfs *buf)
  53{
  54        int retval;
  55
  56        if (!dentry->d_sb->s_op->statfs)
  57                return -ENOSYS;
  58
  59        memset(buf, 0, sizeof(*buf));
  60        retval = security_sb_statfs(dentry);
  61        if (retval)
  62                return retval;
  63        retval = dentry->d_sb->s_op->statfs(dentry, buf);
  64        if (retval == 0 && buf->f_frsize == 0)
  65                buf->f_frsize = buf->f_bsize;
  66        return retval;
  67}
  68
  69int vfs_statfs(const struct path *path, struct kstatfs *buf)
  70{
  71        int error;
  72
  73        error = statfs_by_dentry(path->dentry, buf);
  74        if (!error)
  75                buf->f_flags = calculate_f_flags(path->mnt);
  76        return error;
  77}
  78EXPORT_SYMBOL(vfs_statfs);
  79
  80int user_statfs(const char __user *pathname, struct kstatfs *st)
  81{
  82        struct path path;
  83        int error;
  84        unsigned int lookup_flags = LOOKUP_FOLLOW|LOOKUP_AUTOMOUNT;
  85retry:
  86        error = user_path_at(AT_FDCWD, pathname, lookup_flags, &path);
  87        if (!error) {
  88                error = vfs_statfs(&path, st);
  89                path_put(&path);
  90                if (retry_estale(error, lookup_flags)) {
  91                        lookup_flags |= LOOKUP_REVAL;
  92                        goto retry;
  93                }
  94        }
  95        return error;
  96}
  97
  98int fd_statfs(int fd, struct kstatfs *st)
  99{
 100        struct fd f = fdget_raw(fd);
 101        int error = -EBADF;
 102        if (f.file) {
 103                error = vfs_statfs(&f.file->f_path, st);
 104                fdput(f);
 105        }
 106        return error;
 107}
 108
 109static int do_statfs_native(struct kstatfs *st, struct statfs __user *p)
 110{
 111        struct statfs buf;
 112
 113        if (sizeof(buf) == sizeof(*st))
 114                memcpy(&buf, st, sizeof(*st));
 115        else {
 116                if (sizeof buf.f_blocks == 4) {
 117                        if ((st->f_blocks | st->f_bfree | st->f_bavail |
 118                             st->f_bsize | st->f_frsize) &
 119                            0xffffffff00000000ULL)
 120                                return -EOVERFLOW;
 121                        /*
 122                         * f_files and f_ffree may be -1; it's okay to stuff
 123                         * that into 32 bits
 124                         */
 125                        if (st->f_files != -1 &&
 126                            (st->f_files & 0xffffffff00000000ULL))
 127                                return -EOVERFLOW;
 128                        if (st->f_ffree != -1 &&
 129                            (st->f_ffree & 0xffffffff00000000ULL))
 130                                return -EOVERFLOW;
 131                }
 132
 133                buf.f_type = st->f_type;
 134                buf.f_bsize = st->f_bsize;
 135                buf.f_blocks = st->f_blocks;
 136                buf.f_bfree = st->f_bfree;
 137                buf.f_bavail = st->f_bavail;
 138                buf.f_files = st->f_files;
 139                buf.f_ffree = st->f_ffree;
 140                buf.f_fsid = st->f_fsid;
 141                buf.f_namelen = st->f_namelen;
 142                buf.f_frsize = st->f_frsize;
 143                buf.f_flags = st->f_flags;
 144                memset(buf.f_spare, 0, sizeof(buf.f_spare));
 145        }
 146        if (copy_to_user(p, &buf, sizeof(buf)))
 147                return -EFAULT;
 148        return 0;
 149}
 150
 151static int do_statfs64(struct kstatfs *st, struct statfs64 __user *p)
 152{
 153        struct statfs64 buf;
 154        if (sizeof(buf) == sizeof(*st))
 155                memcpy(&buf, st, sizeof(*st));
 156        else {
 157                buf.f_type = st->f_type;
 158                buf.f_bsize = st->f_bsize;
 159                buf.f_blocks = st->f_blocks;
 160                buf.f_bfree = st->f_bfree;
 161                buf.f_bavail = st->f_bavail;
 162                buf.f_files = st->f_files;
 163                buf.f_ffree = st->f_ffree;
 164                buf.f_fsid = st->f_fsid;
 165                buf.f_namelen = st->f_namelen;
 166                buf.f_frsize = st->f_frsize;
 167                buf.f_flags = st->f_flags;
 168                memset(buf.f_spare, 0, sizeof(buf.f_spare));
 169        }
 170        if (copy_to_user(p, &buf, sizeof(buf)))
 171                return -EFAULT;
 172        return 0;
 173}
 174
 175SYSCALL_DEFINE2(statfs, const char __user *, pathname, struct statfs __user *, buf)
 176{
 177        struct kstatfs st;
 178        int error = user_statfs(pathname, &st);
 179        if (!error)
 180                error = do_statfs_native(&st, buf);
 181        return error;
 182}
 183
 184SYSCALL_DEFINE3(statfs64, const char __user *, pathname, size_t, sz, struct statfs64 __user *, buf)
 185{
 186        struct kstatfs st;
 187        int error;
 188        if (sz != sizeof(*buf))
 189                return -EINVAL;
 190        error = user_statfs(pathname, &st);
 191        if (!error)
 192                error = do_statfs64(&st, buf);
 193        return error;
 194}
 195
 196SYSCALL_DEFINE2(fstatfs, unsigned int, fd, struct statfs __user *, buf)
 197{
 198        struct kstatfs st;
 199        int error = fd_statfs(fd, &st);
 200        if (!error)
 201                error = do_statfs_native(&st, buf);
 202        return error;
 203}
 204
 205SYSCALL_DEFINE3(fstatfs64, unsigned int, fd, size_t, sz, struct statfs64 __user *, buf)
 206{
 207        struct kstatfs st;
 208        int error;
 209
 210        if (sz != sizeof(*buf))
 211                return -EINVAL;
 212
 213        error = fd_statfs(fd, &st);
 214        if (!error)
 215                error = do_statfs64(&st, buf);
 216        return error;
 217}
 218
 219int vfs_ustat(dev_t dev, struct kstatfs *sbuf)
 220{
 221        struct super_block *s = user_get_super(dev);
 222        int err;
 223        if (!s)
 224                return -EINVAL;
 225
 226        err = statfs_by_dentry(s->s_root, sbuf);
 227        drop_super(s);
 228        return err;
 229}
 230
 231SYSCALL_DEFINE2(ustat, unsigned, dev, struct ustat __user *, ubuf)
 232{
 233        struct ustat tmp;
 234        struct kstatfs sbuf;
 235        int err = vfs_ustat(new_decode_dev(dev), &sbuf);
 236        if (err)
 237                return err;
 238
 239        memset(&tmp,0,sizeof(struct ustat));
 240        tmp.f_tfree = sbuf.f_bfree;
 241        tmp.f_tinode = sbuf.f_ffree;
 242
 243        return copy_to_user(ubuf, &tmp, sizeof(struct ustat)) ? -EFAULT : 0;
 244}
 245
 246#ifdef CONFIG_COMPAT
 247static int put_compat_statfs(struct compat_statfs __user *ubuf, struct kstatfs *kbuf)
 248{
 249        struct compat_statfs buf;
 250        if (sizeof ubuf->f_blocks == 4) {
 251                if ((kbuf->f_blocks | kbuf->f_bfree | kbuf->f_bavail |
 252                     kbuf->f_bsize | kbuf->f_frsize) & 0xffffffff00000000ULL)
 253                        return -EOVERFLOW;
 254                /* f_files and f_ffree may be -1; it's okay
 255                 * to stuff that into 32 bits */
 256                if (kbuf->f_files != 0xffffffffffffffffULL
 257                 && (kbuf->f_files & 0xffffffff00000000ULL))
 258                        return -EOVERFLOW;
 259                if (kbuf->f_ffree != 0xffffffffffffffffULL
 260                 && (kbuf->f_ffree & 0xffffffff00000000ULL))
 261                        return -EOVERFLOW;
 262        }
 263        memset(&buf, 0, sizeof(struct compat_statfs));
 264        buf.f_type = kbuf->f_type;
 265        buf.f_bsize = kbuf->f_bsize;
 266        buf.f_blocks = kbuf->f_blocks;
 267        buf.f_bfree = kbuf->f_bfree;
 268        buf.f_bavail = kbuf->f_bavail;
 269        buf.f_files = kbuf->f_files;
 270        buf.f_ffree = kbuf->f_ffree;
 271        buf.f_namelen = kbuf->f_namelen;
 272        buf.f_fsid.val[0] = kbuf->f_fsid.val[0];
 273        buf.f_fsid.val[1] = kbuf->f_fsid.val[1];
 274        buf.f_frsize = kbuf->f_frsize;
 275        buf.f_flags = kbuf->f_flags;
 276        if (copy_to_user(ubuf, &buf, sizeof(struct compat_statfs)))
 277                return -EFAULT;
 278        return 0;
 279}
 280
 281/*
 282 * The following statfs calls are copies of code from fs/statfs.c and
 283 * should be checked against those from time to time
 284 */
 285COMPAT_SYSCALL_DEFINE2(statfs, const char __user *, pathname, struct compat_statfs __user *, buf)
 286{
 287        struct kstatfs tmp;
 288        int error = user_statfs(pathname, &tmp);
 289        if (!error)
 290                error = put_compat_statfs(buf, &tmp);
 291        return error;
 292}
 293
 294COMPAT_SYSCALL_DEFINE2(fstatfs, unsigned int, fd, struct compat_statfs __user *, buf)
 295{
 296        struct kstatfs tmp;
 297        int error = fd_statfs(fd, &tmp);
 298        if (!error)
 299                error = put_compat_statfs(buf, &tmp);
 300        return error;
 301}
 302
 303static int put_compat_statfs64(struct compat_statfs64 __user *ubuf, struct kstatfs *kbuf)
 304{
 305        struct compat_statfs64 buf;
 306        if (sizeof(ubuf->f_bsize) == 4) {
 307                if ((kbuf->f_type | kbuf->f_bsize | kbuf->f_namelen |
 308                     kbuf->f_frsize | kbuf->f_flags) & 0xffffffff00000000ULL)
 309                        return -EOVERFLOW;
 310                /* f_files and f_ffree may be -1; it's okay
 311                 * to stuff that into 32 bits */
 312                if (kbuf->f_files != 0xffffffffffffffffULL
 313                 && (kbuf->f_files & 0xffffffff00000000ULL))
 314                        return -EOVERFLOW;
 315                if (kbuf->f_ffree != 0xffffffffffffffffULL
 316                 && (kbuf->f_ffree & 0xffffffff00000000ULL))
 317                        return -EOVERFLOW;
 318        }
 319        memset(&buf, 0, sizeof(struct compat_statfs64));
 320        buf.f_type = kbuf->f_type;
 321        buf.f_bsize = kbuf->f_bsize;
 322        buf.f_blocks = kbuf->f_blocks;
 323        buf.f_bfree = kbuf->f_bfree;
 324        buf.f_bavail = kbuf->f_bavail;
 325        buf.f_files = kbuf->f_files;
 326        buf.f_ffree = kbuf->f_ffree;
 327        buf.f_namelen = kbuf->f_namelen;
 328        buf.f_fsid.val[0] = kbuf->f_fsid.val[0];
 329        buf.f_fsid.val[1] = kbuf->f_fsid.val[1];
 330        buf.f_frsize = kbuf->f_frsize;
 331        buf.f_flags = kbuf->f_flags;
 332        if (copy_to_user(ubuf, &buf, sizeof(struct compat_statfs64)))
 333                return -EFAULT;
 334        return 0;
 335}
 336
 337COMPAT_SYSCALL_DEFINE3(statfs64, const char __user *, pathname, compat_size_t, sz, struct compat_statfs64 __user *, buf)
 338{
 339        struct kstatfs tmp;
 340        int error;
 341
 342        if (sz != sizeof(*buf))
 343                return -EINVAL;
 344
 345        error = user_statfs(pathname, &tmp);
 346        if (!error)
 347                error = put_compat_statfs64(buf, &tmp);
 348        return error;
 349}
 350
 351COMPAT_SYSCALL_DEFINE3(fstatfs64, unsigned int, fd, compat_size_t, sz, struct compat_statfs64 __user *, buf)
 352{
 353        struct kstatfs tmp;
 354        int error;
 355
 356        if (sz != sizeof(*buf))
 357                return -EINVAL;
 358
 359        error = fd_statfs(fd, &tmp);
 360        if (!error)
 361                error = put_compat_statfs64(buf, &tmp);
 362        return error;
 363}
 364
 365/*
 366 * This is a copy of sys_ustat, just dealing with a structure layout.
 367 * Given how simple this syscall is that apporach is more maintainable
 368 * than the various conversion hacks.
 369 */
 370COMPAT_SYSCALL_DEFINE2(ustat, unsigned, dev, struct compat_ustat __user *, u)
 371{
 372        struct compat_ustat tmp;
 373        struct kstatfs sbuf;
 374        int err = vfs_ustat(new_decode_dev(dev), &sbuf);
 375        if (err)
 376                return err;
 377
 378        memset(&tmp, 0, sizeof(struct compat_ustat));
 379        tmp.f_tfree = sbuf.f_bfree;
 380        tmp.f_tinode = sbuf.f_ffree;
 381        if (copy_to_user(u, &tmp, sizeof(struct compat_ustat)))
 382                return -EFAULT;
 383        return 0;
 384}
 385#endif
 386