compat.c 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119
  1. #include <linux/syscalls.h>
  2. #include <linux/compat.h>
  3. #include <linux/quotaops.h>
  4. /*
  5. * This code works only for 32 bit quota tools over 64 bit OS (x86_64, ia64)
  6. * and is necessary due to alignment problems.
  7. */
  8. struct compat_if_dqblk {
  9. compat_u64 dqb_bhardlimit;
  10. compat_u64 dqb_bsoftlimit;
  11. compat_u64 dqb_curspace;
  12. compat_u64 dqb_ihardlimit;
  13. compat_u64 dqb_isoftlimit;
  14. compat_u64 dqb_curinodes;
  15. compat_u64 dqb_btime;
  16. compat_u64 dqb_itime;
  17. compat_uint_t dqb_valid;
  18. };
  19. /* XFS structures */
  20. struct compat_fs_qfilestat {
  21. compat_u64 dqb_bhardlimit;
  22. compat_u64 qfs_nblks;
  23. compat_uint_t qfs_nextents;
  24. };
  25. struct compat_fs_quota_stat {
  26. __s8 qs_version;
  27. __u16 qs_flags;
  28. __s8 qs_pad;
  29. struct compat_fs_qfilestat qs_uquota;
  30. struct compat_fs_qfilestat qs_gquota;
  31. compat_uint_t qs_incoredqs;
  32. compat_int_t qs_btimelimit;
  33. compat_int_t qs_itimelimit;
  34. compat_int_t qs_rtbtimelimit;
  35. __u16 qs_bwarnlimit;
  36. __u16 qs_iwarnlimit;
  37. };
  38. asmlinkage long sys32_quotactl(unsigned int cmd, const char __user *special,
  39. qid_t id, void __user *addr)
  40. {
  41. unsigned int cmds;
  42. struct if_dqblk __user *dqblk;
  43. struct compat_if_dqblk __user *compat_dqblk;
  44. struct fs_quota_stat __user *fsqstat;
  45. struct compat_fs_quota_stat __user *compat_fsqstat;
  46. compat_uint_t data;
  47. u16 xdata;
  48. long ret;
  49. cmds = cmd >> SUBCMDSHIFT;
  50. switch (cmds) {
  51. case Q_GETQUOTA:
  52. dqblk = compat_alloc_user_space(sizeof(struct if_dqblk));
  53. compat_dqblk = addr;
  54. ret = sys_quotactl(cmd, special, id, dqblk);
  55. if (ret)
  56. break;
  57. if (copy_in_user(compat_dqblk, dqblk, sizeof(*compat_dqblk)) ||
  58. get_user(data, &dqblk->dqb_valid) ||
  59. put_user(data, &compat_dqblk->dqb_valid))
  60. ret = -EFAULT;
  61. break;
  62. case Q_SETQUOTA:
  63. dqblk = compat_alloc_user_space(sizeof(struct if_dqblk));
  64. compat_dqblk = addr;
  65. ret = -EFAULT;
  66. if (copy_in_user(dqblk, compat_dqblk, sizeof(*compat_dqblk)) ||
  67. get_user(data, &compat_dqblk->dqb_valid) ||
  68. put_user(data, &dqblk->dqb_valid))
  69. break;
  70. ret = sys_quotactl(cmd, special, id, dqblk);
  71. break;
  72. case Q_XGETQSTAT:
  73. fsqstat = compat_alloc_user_space(sizeof(struct fs_quota_stat));
  74. compat_fsqstat = addr;
  75. ret = sys_quotactl(cmd, special, id, fsqstat);
  76. if (ret)
  77. break;
  78. ret = -EFAULT;
  79. /* Copying qs_version, qs_flags, qs_pad */
  80. if (copy_in_user(compat_fsqstat, fsqstat,
  81. offsetof(struct compat_fs_quota_stat, qs_uquota)))
  82. break;
  83. /* Copying qs_uquota */
  84. if (copy_in_user(&compat_fsqstat->qs_uquota,
  85. &fsqstat->qs_uquota,
  86. sizeof(compat_fsqstat->qs_uquota)) ||
  87. get_user(data, &fsqstat->qs_uquota.qfs_nextents) ||
  88. put_user(data, &compat_fsqstat->qs_uquota.qfs_nextents))
  89. break;
  90. /* Copying qs_gquota */
  91. if (copy_in_user(&compat_fsqstat->qs_gquota,
  92. &fsqstat->qs_gquota,
  93. sizeof(compat_fsqstat->qs_gquota)) ||
  94. get_user(data, &fsqstat->qs_gquota.qfs_nextents) ||
  95. put_user(data, &compat_fsqstat->qs_gquota.qfs_nextents))
  96. break;
  97. /* Copying the rest */
  98. if (copy_in_user(&compat_fsqstat->qs_incoredqs,
  99. &fsqstat->qs_incoredqs,
  100. sizeof(struct compat_fs_quota_stat) -
  101. offsetof(struct compat_fs_quota_stat, qs_incoredqs)) ||
  102. get_user(xdata, &fsqstat->qs_iwarnlimit) ||
  103. put_user(xdata, &compat_fsqstat->qs_iwarnlimit))
  104. break;
  105. ret = 0;
  106. break;
  107. default:
  108. ret = sys_quotactl(cmd, special, id, addr);
  109. }
  110. return ret;
  111. }