109c434b8SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only 2884d179dSJan Kara /* 3884d179dSJan Kara * vfsv0 quota IO operations on file 4884d179dSJan Kara */ 5884d179dSJan Kara 6884d179dSJan Kara #include <linux/errno.h> 7884d179dSJan Kara #include <linux/fs.h> 8884d179dSJan Kara #include <linux/mount.h> 9884d179dSJan Kara #include <linux/dqblk_v2.h> 10884d179dSJan Kara #include <linux/kernel.h> 11884d179dSJan Kara #include <linux/init.h> 12884d179dSJan Kara #include <linux/module.h> 13884d179dSJan Kara #include <linux/slab.h> 14884d179dSJan Kara #include <linux/quotaops.h> 15884d179dSJan Kara 16884d179dSJan Kara #include <asm/byteorder.h> 17884d179dSJan Kara 18884d179dSJan Kara #include "quota_tree.h" 19884d179dSJan Kara 20884d179dSJan Kara MODULE_AUTHOR("Jan Kara"); 21884d179dSJan Kara MODULE_DESCRIPTION("Quota trie support"); 22884d179dSJan Kara MODULE_LICENSE("GPL"); 23884d179dSJan Kara 24884d179dSJan Kara #define __QUOTA_QT_PARANOIA 25884d179dSJan Kara 260066373dSJan Kara static int __get_index(struct qtree_mem_dqinfo *info, qid_t id, int depth) 27884d179dSJan Kara { 28884d179dSJan Kara unsigned int epb = info->dqi_usable_bs >> 2; 29884d179dSJan Kara 30884d179dSJan Kara depth = info->dqi_qtree_depth - depth - 1; 31884d179dSJan Kara while (depth--) 32884d179dSJan Kara id /= epb; 33884d179dSJan Kara return id % epb; 34884d179dSJan Kara } 35884d179dSJan Kara 360066373dSJan Kara static int get_index(struct qtree_mem_dqinfo *info, struct kqid qid, int depth) 370066373dSJan Kara { 380066373dSJan Kara qid_t id = from_kqid(&init_user_ns, qid); 390066373dSJan Kara 400066373dSJan Kara return __get_index(info, id, depth); 410066373dSJan Kara } 420066373dSJan Kara 43884d179dSJan Kara /* Number of entries in one blocks */ 447a2435d8SJan Kara static int qtree_dqstr_in_blk(struct qtree_mem_dqinfo *info) 45884d179dSJan Kara { 46884d179dSJan Kara return (info->dqi_usable_bs - sizeof(struct qt_disk_dqdbheader)) 47884d179dSJan Kara / info->dqi_entry_size; 48884d179dSJan Kara } 49884d179dSJan Kara 507a2435d8SJan Kara static ssize_t read_blk(struct qtree_mem_dqinfo *info, uint blk, char *buf) 51884d179dSJan Kara { 52884d179dSJan Kara struct super_block *sb = info->dqi_sb; 53884d179dSJan Kara 54884d179dSJan Kara memset(buf, 0, info->dqi_usable_bs); 55d26ac1a8SJan Kara return sb->s_op->quota_read(sb, info->dqi_type, buf, 5610f04d40SJan Kara info->dqi_usable_bs, (loff_t)blk << info->dqi_blocksize_bits); 57884d179dSJan Kara } 58884d179dSJan Kara 597a2435d8SJan Kara static ssize_t write_blk(struct qtree_mem_dqinfo *info, uint blk, char *buf) 60884d179dSJan Kara { 61884d179dSJan Kara struct super_block *sb = info->dqi_sb; 621907131bSJiaying Zhang ssize_t ret; 63884d179dSJan Kara 641907131bSJiaying Zhang ret = sb->s_op->quota_write(sb, info->dqi_type, buf, 6510f04d40SJan Kara info->dqi_usable_bs, (loff_t)blk << info->dqi_blocksize_bits); 661907131bSJiaying Zhang if (ret != info->dqi_usable_bs) { 67fb5ffb0eSJiaying Zhang quota_error(sb, "dquota write failed"); 681907131bSJiaying Zhang if (ret >= 0) 691907131bSJiaying Zhang ret = -EIO; 701907131bSJiaying Zhang } 711907131bSJiaying Zhang return ret; 72884d179dSJan Kara } 73884d179dSJan Kara 746c8ea8b8SZhihao Cheng static inline int do_check_range(struct super_block *sb, const char *val_name, 756c8ea8b8SZhihao Cheng uint val, uint min_val, uint max_val) 766c8ea8b8SZhihao Cheng { 776c8ea8b8SZhihao Cheng if (val < min_val || val > max_val) { 786c8ea8b8SZhihao Cheng quota_error(sb, "Getting %s %u out of range %u-%u", 796c8ea8b8SZhihao Cheng val_name, val, min_val, max_val); 806c8ea8b8SZhihao Cheng return -EUCLEAN; 816c8ea8b8SZhihao Cheng } 826c8ea8b8SZhihao Cheng 836c8ea8b8SZhihao Cheng return 0; 846c8ea8b8SZhihao Cheng } 856c8ea8b8SZhihao Cheng 866c8ea8b8SZhihao Cheng static int check_dquot_block_header(struct qtree_mem_dqinfo *info, 876c8ea8b8SZhihao Cheng struct qt_disk_dqdbheader *dh) 886c8ea8b8SZhihao Cheng { 896c8ea8b8SZhihao Cheng int err = 0; 906c8ea8b8SZhihao Cheng 916c8ea8b8SZhihao Cheng err = do_check_range(info->dqi_sb, "dqdh_next_free", 926c8ea8b8SZhihao Cheng le32_to_cpu(dh->dqdh_next_free), 0, 936c8ea8b8SZhihao Cheng info->dqi_blocks - 1); 946c8ea8b8SZhihao Cheng if (err) 956c8ea8b8SZhihao Cheng return err; 966c8ea8b8SZhihao Cheng err = do_check_range(info->dqi_sb, "dqdh_prev_free", 976c8ea8b8SZhihao Cheng le32_to_cpu(dh->dqdh_prev_free), 0, 986c8ea8b8SZhihao Cheng info->dqi_blocks - 1); 99191249f7SZhihao Cheng if (err) 100191249f7SZhihao Cheng return err; 101191249f7SZhihao Cheng err = do_check_range(info->dqi_sb, "dqdh_entries", 102191249f7SZhihao Cheng le16_to_cpu(dh->dqdh_entries), 0, 103191249f7SZhihao Cheng qtree_dqstr_in_blk(info)); 1046c8ea8b8SZhihao Cheng 1056c8ea8b8SZhihao Cheng return err; 1066c8ea8b8SZhihao Cheng } 1076c8ea8b8SZhihao Cheng 108884d179dSJan Kara /* Remove empty block from list and return it */ 109884d179dSJan Kara static int get_free_dqblk(struct qtree_mem_dqinfo *info) 110884d179dSJan Kara { 111*a1e1b2beSJan Kara char *buf = kmalloc(info->dqi_usable_bs, GFP_KERNEL); 112884d179dSJan Kara struct qt_disk_dqdbheader *dh = (struct qt_disk_dqdbheader *)buf; 113884d179dSJan Kara int ret, blk; 114884d179dSJan Kara 115884d179dSJan Kara if (!buf) 116884d179dSJan Kara return -ENOMEM; 117884d179dSJan Kara if (info->dqi_free_blk) { 118884d179dSJan Kara blk = info->dqi_free_blk; 119884d179dSJan Kara ret = read_blk(info, blk, buf); 120884d179dSJan Kara if (ret < 0) 121884d179dSJan Kara goto out_buf; 1226c8ea8b8SZhihao Cheng ret = check_dquot_block_header(info, dh); 1236c8ea8b8SZhihao Cheng if (ret) 1246c8ea8b8SZhihao Cheng goto out_buf; 125884d179dSJan Kara info->dqi_free_blk = le32_to_cpu(dh->dqdh_next_free); 126884d179dSJan Kara } 127884d179dSJan Kara else { 128884d179dSJan Kara memset(buf, 0, info->dqi_usable_bs); 129884d179dSJan Kara /* Assure block allocation... */ 130884d179dSJan Kara ret = write_blk(info, info->dqi_blocks, buf); 131884d179dSJan Kara if (ret < 0) 132884d179dSJan Kara goto out_buf; 133884d179dSJan Kara blk = info->dqi_blocks++; 134884d179dSJan Kara } 135884d179dSJan Kara mark_info_dirty(info->dqi_sb, info->dqi_type); 136884d179dSJan Kara ret = blk; 137884d179dSJan Kara out_buf: 138d26ac1a8SJan Kara kfree(buf); 139884d179dSJan Kara return ret; 140884d179dSJan Kara } 141884d179dSJan Kara 142884d179dSJan Kara /* Insert empty block to the list */ 143d26ac1a8SJan Kara static int put_free_dqblk(struct qtree_mem_dqinfo *info, char *buf, uint blk) 144884d179dSJan Kara { 145884d179dSJan Kara struct qt_disk_dqdbheader *dh = (struct qt_disk_dqdbheader *)buf; 146884d179dSJan Kara int err; 147884d179dSJan Kara 148884d179dSJan Kara dh->dqdh_next_free = cpu_to_le32(info->dqi_free_blk); 149884d179dSJan Kara dh->dqdh_prev_free = cpu_to_le32(0); 150884d179dSJan Kara dh->dqdh_entries = cpu_to_le16(0); 151884d179dSJan Kara err = write_blk(info, blk, buf); 152884d179dSJan Kara if (err < 0) 153884d179dSJan Kara return err; 154884d179dSJan Kara info->dqi_free_blk = blk; 155884d179dSJan Kara mark_info_dirty(info->dqi_sb, info->dqi_type); 156884d179dSJan Kara return 0; 157884d179dSJan Kara } 158884d179dSJan Kara 159884d179dSJan Kara /* Remove given block from the list of blocks with free entries */ 160268157baSJan Kara static int remove_free_dqentry(struct qtree_mem_dqinfo *info, char *buf, 161268157baSJan Kara uint blk) 162884d179dSJan Kara { 163*a1e1b2beSJan Kara char *tmpbuf = kmalloc(info->dqi_usable_bs, GFP_KERNEL); 164884d179dSJan Kara struct qt_disk_dqdbheader *dh = (struct qt_disk_dqdbheader *)buf; 165884d179dSJan Kara uint nextblk = le32_to_cpu(dh->dqdh_next_free); 166884d179dSJan Kara uint prevblk = le32_to_cpu(dh->dqdh_prev_free); 167884d179dSJan Kara int err; 168884d179dSJan Kara 169884d179dSJan Kara if (!tmpbuf) 170884d179dSJan Kara return -ENOMEM; 171884d179dSJan Kara if (nextblk) { 172884d179dSJan Kara err = read_blk(info, nextblk, tmpbuf); 173884d179dSJan Kara if (err < 0) 174884d179dSJan Kara goto out_buf; 175884d179dSJan Kara ((struct qt_disk_dqdbheader *)tmpbuf)->dqdh_prev_free = 176884d179dSJan Kara dh->dqdh_prev_free; 177884d179dSJan Kara err = write_blk(info, nextblk, tmpbuf); 178884d179dSJan Kara if (err < 0) 179884d179dSJan Kara goto out_buf; 180884d179dSJan Kara } 181884d179dSJan Kara if (prevblk) { 182884d179dSJan Kara err = read_blk(info, prevblk, tmpbuf); 183884d179dSJan Kara if (err < 0) 184884d179dSJan Kara goto out_buf; 185884d179dSJan Kara ((struct qt_disk_dqdbheader *)tmpbuf)->dqdh_next_free = 186884d179dSJan Kara dh->dqdh_next_free; 187884d179dSJan Kara err = write_blk(info, prevblk, tmpbuf); 188884d179dSJan Kara if (err < 0) 189884d179dSJan Kara goto out_buf; 190884d179dSJan Kara } else { 191884d179dSJan Kara info->dqi_free_entry = nextblk; 192884d179dSJan Kara mark_info_dirty(info->dqi_sb, info->dqi_type); 193884d179dSJan Kara } 194d26ac1a8SJan Kara kfree(tmpbuf); 195884d179dSJan Kara dh->dqdh_next_free = dh->dqdh_prev_free = cpu_to_le32(0); 196884d179dSJan Kara /* No matter whether write succeeds block is out of list */ 197884d179dSJan Kara if (write_blk(info, blk, buf) < 0) 198fb5ffb0eSJiaying Zhang quota_error(info->dqi_sb, "Can't write block (%u) " 199fb5ffb0eSJiaying Zhang "with free entries", blk); 200884d179dSJan Kara return 0; 201884d179dSJan Kara out_buf: 202d26ac1a8SJan Kara kfree(tmpbuf); 203884d179dSJan Kara return err; 204884d179dSJan Kara } 205884d179dSJan Kara 206884d179dSJan Kara /* Insert given block to the beginning of list with free entries */ 207268157baSJan Kara static int insert_free_dqentry(struct qtree_mem_dqinfo *info, char *buf, 208268157baSJan Kara uint blk) 209884d179dSJan Kara { 210*a1e1b2beSJan Kara char *tmpbuf = kmalloc(info->dqi_usable_bs, GFP_KERNEL); 211884d179dSJan Kara struct qt_disk_dqdbheader *dh = (struct qt_disk_dqdbheader *)buf; 212884d179dSJan Kara int err; 213884d179dSJan Kara 214884d179dSJan Kara if (!tmpbuf) 215884d179dSJan Kara return -ENOMEM; 216884d179dSJan Kara dh->dqdh_next_free = cpu_to_le32(info->dqi_free_entry); 217884d179dSJan Kara dh->dqdh_prev_free = cpu_to_le32(0); 218884d179dSJan Kara err = write_blk(info, blk, buf); 219884d179dSJan Kara if (err < 0) 220884d179dSJan Kara goto out_buf; 221884d179dSJan Kara if (info->dqi_free_entry) { 222884d179dSJan Kara err = read_blk(info, info->dqi_free_entry, tmpbuf); 223884d179dSJan Kara if (err < 0) 224884d179dSJan Kara goto out_buf; 225884d179dSJan Kara ((struct qt_disk_dqdbheader *)tmpbuf)->dqdh_prev_free = 226884d179dSJan Kara cpu_to_le32(blk); 227884d179dSJan Kara err = write_blk(info, info->dqi_free_entry, tmpbuf); 228884d179dSJan Kara if (err < 0) 229884d179dSJan Kara goto out_buf; 230884d179dSJan Kara } 231d26ac1a8SJan Kara kfree(tmpbuf); 232884d179dSJan Kara info->dqi_free_entry = blk; 233884d179dSJan Kara mark_info_dirty(info->dqi_sb, info->dqi_type); 234884d179dSJan Kara return 0; 235884d179dSJan Kara out_buf: 236d26ac1a8SJan Kara kfree(tmpbuf); 237884d179dSJan Kara return err; 238884d179dSJan Kara } 239884d179dSJan Kara 240884d179dSJan Kara /* Is the entry in the block free? */ 241884d179dSJan Kara int qtree_entry_unused(struct qtree_mem_dqinfo *info, char *disk) 242884d179dSJan Kara { 243884d179dSJan Kara int i; 244884d179dSJan Kara 245884d179dSJan Kara for (i = 0; i < info->dqi_entry_size; i++) 246884d179dSJan Kara if (disk[i]) 247884d179dSJan Kara return 0; 248884d179dSJan Kara return 1; 249884d179dSJan Kara } 250884d179dSJan Kara EXPORT_SYMBOL(qtree_entry_unused); 251884d179dSJan Kara 252884d179dSJan Kara /* Find space for dquot */ 253884d179dSJan Kara static uint find_free_dqentry(struct qtree_mem_dqinfo *info, 254884d179dSJan Kara struct dquot *dquot, int *err) 255884d179dSJan Kara { 256884d179dSJan Kara uint blk, i; 257884d179dSJan Kara struct qt_disk_dqdbheader *dh; 258*a1e1b2beSJan Kara char *buf = kmalloc(info->dqi_usable_bs, GFP_KERNEL); 259884d179dSJan Kara char *ddquot; 260884d179dSJan Kara 261884d179dSJan Kara *err = 0; 262884d179dSJan Kara if (!buf) { 263884d179dSJan Kara *err = -ENOMEM; 264884d179dSJan Kara return 0; 265884d179dSJan Kara } 266884d179dSJan Kara dh = (struct qt_disk_dqdbheader *)buf; 267884d179dSJan Kara if (info->dqi_free_entry) { 268884d179dSJan Kara blk = info->dqi_free_entry; 269884d179dSJan Kara *err = read_blk(info, blk, buf); 270884d179dSJan Kara if (*err < 0) 271884d179dSJan Kara goto out_buf; 2726c8ea8b8SZhihao Cheng *err = check_dquot_block_header(info, dh); 2736c8ea8b8SZhihao Cheng if (*err) 2746c8ea8b8SZhihao Cheng goto out_buf; 275884d179dSJan Kara } else { 276884d179dSJan Kara blk = get_free_dqblk(info); 277884d179dSJan Kara if ((int)blk < 0) { 278884d179dSJan Kara *err = blk; 279d26ac1a8SJan Kara kfree(buf); 280884d179dSJan Kara return 0; 281884d179dSJan Kara } 282884d179dSJan Kara memset(buf, 0, info->dqi_usable_bs); 283268157baSJan Kara /* This is enough as the block is already zeroed and the entry 284268157baSJan Kara * list is empty... */ 285884d179dSJan Kara info->dqi_free_entry = blk; 2864c376dcaSEric W. Biederman mark_info_dirty(dquot->dq_sb, dquot->dq_id.type); 287884d179dSJan Kara } 288884d179dSJan Kara /* Block will be full? */ 289884d179dSJan Kara if (le16_to_cpu(dh->dqdh_entries) + 1 >= qtree_dqstr_in_blk(info)) { 290884d179dSJan Kara *err = remove_free_dqentry(info, buf, blk); 291884d179dSJan Kara if (*err < 0) { 292fb5ffb0eSJiaying Zhang quota_error(dquot->dq_sb, "Can't remove block (%u) " 293fb5ffb0eSJiaying Zhang "from entry free list", blk); 294884d179dSJan Kara goto out_buf; 295884d179dSJan Kara } 296884d179dSJan Kara } 297884d179dSJan Kara le16_add_cpu(&dh->dqdh_entries, 1); 298884d179dSJan Kara /* Find free structure in block */ 299268157baSJan Kara ddquot = buf + sizeof(struct qt_disk_dqdbheader); 300268157baSJan Kara for (i = 0; i < qtree_dqstr_in_blk(info); i++) { 301268157baSJan Kara if (qtree_entry_unused(info, ddquot)) 302268157baSJan Kara break; 303268157baSJan Kara ddquot += info->dqi_entry_size; 304268157baSJan Kara } 305884d179dSJan Kara #ifdef __QUOTA_QT_PARANOIA 306884d179dSJan Kara if (i == qtree_dqstr_in_blk(info)) { 307fb5ffb0eSJiaying Zhang quota_error(dquot->dq_sb, "Data block full but it shouldn't"); 308884d179dSJan Kara *err = -EIO; 309884d179dSJan Kara goto out_buf; 310884d179dSJan Kara } 311884d179dSJan Kara #endif 312884d179dSJan Kara *err = write_blk(info, blk, buf); 313884d179dSJan Kara if (*err < 0) { 314fb5ffb0eSJiaying Zhang quota_error(dquot->dq_sb, "Can't write quota data block %u", 315fb5ffb0eSJiaying Zhang blk); 316884d179dSJan Kara goto out_buf; 317884d179dSJan Kara } 31810f04d40SJan Kara dquot->dq_off = ((loff_t)blk << info->dqi_blocksize_bits) + 319884d179dSJan Kara sizeof(struct qt_disk_dqdbheader) + 320884d179dSJan Kara i * info->dqi_entry_size; 321d26ac1a8SJan Kara kfree(buf); 322884d179dSJan Kara return blk; 323884d179dSJan Kara out_buf: 324d26ac1a8SJan Kara kfree(buf); 325884d179dSJan Kara return 0; 326884d179dSJan Kara } 327884d179dSJan Kara 328884d179dSJan Kara /* Insert reference to structure into the trie */ 329884d179dSJan Kara static int do_insert_tree(struct qtree_mem_dqinfo *info, struct dquot *dquot, 330884d179dSJan Kara uint *treeblk, int depth) 331884d179dSJan Kara { 332*a1e1b2beSJan Kara char *buf = kmalloc(info->dqi_usable_bs, GFP_KERNEL); 333884d179dSJan Kara int ret = 0, newson = 0, newact = 0; 334884d179dSJan Kara __le32 *ref; 335884d179dSJan Kara uint newblk; 336884d179dSJan Kara 337884d179dSJan Kara if (!buf) 338884d179dSJan Kara return -ENOMEM; 339884d179dSJan Kara if (!*treeblk) { 340884d179dSJan Kara ret = get_free_dqblk(info); 341884d179dSJan Kara if (ret < 0) 342884d179dSJan Kara goto out_buf; 343884d179dSJan Kara *treeblk = ret; 344884d179dSJan Kara memset(buf, 0, info->dqi_usable_bs); 345884d179dSJan Kara newact = 1; 346884d179dSJan Kara } else { 347884d179dSJan Kara ret = read_blk(info, *treeblk, buf); 348884d179dSJan Kara if (ret < 0) { 349fb5ffb0eSJiaying Zhang quota_error(dquot->dq_sb, "Can't read tree quota " 350fb5ffb0eSJiaying Zhang "block %u", *treeblk); 351884d179dSJan Kara goto out_buf; 352884d179dSJan Kara } 353884d179dSJan Kara } 354884d179dSJan Kara ref = (__le32 *)buf; 355884d179dSJan Kara newblk = le32_to_cpu(ref[get_index(info, dquot->dq_id, depth)]); 356191249f7SZhihao Cheng ret = do_check_range(dquot->dq_sb, "block", newblk, 0, 357191249f7SZhihao Cheng info->dqi_blocks - 1); 358191249f7SZhihao Cheng if (ret) 359191249f7SZhihao Cheng goto out_buf; 360884d179dSJan Kara if (!newblk) 361884d179dSJan Kara newson = 1; 362884d179dSJan Kara if (depth == info->dqi_qtree_depth - 1) { 363884d179dSJan Kara #ifdef __QUOTA_QT_PARANOIA 364884d179dSJan Kara if (newblk) { 365fb5ffb0eSJiaying Zhang quota_error(dquot->dq_sb, "Inserting already present " 366fb5ffb0eSJiaying Zhang "quota entry (block %u)", 367884d179dSJan Kara le32_to_cpu(ref[get_index(info, 368884d179dSJan Kara dquot->dq_id, depth)])); 369884d179dSJan Kara ret = -EIO; 370884d179dSJan Kara goto out_buf; 371884d179dSJan Kara } 372884d179dSJan Kara #endif 373884d179dSJan Kara newblk = find_free_dqentry(info, dquot, &ret); 374884d179dSJan Kara } else { 375884d179dSJan Kara ret = do_insert_tree(info, dquot, &newblk, depth+1); 376884d179dSJan Kara } 377884d179dSJan Kara if (newson && ret >= 0) { 378884d179dSJan Kara ref[get_index(info, dquot->dq_id, depth)] = 379884d179dSJan Kara cpu_to_le32(newblk); 380884d179dSJan Kara ret = write_blk(info, *treeblk, buf); 381884d179dSJan Kara } else if (newact && ret < 0) { 382884d179dSJan Kara put_free_dqblk(info, buf, *treeblk); 383884d179dSJan Kara } 384884d179dSJan Kara out_buf: 385d26ac1a8SJan Kara kfree(buf); 386884d179dSJan Kara return ret; 387884d179dSJan Kara } 388884d179dSJan Kara 389884d179dSJan Kara /* Wrapper for inserting quota structure into tree */ 390884d179dSJan Kara static inline int dq_insert_tree(struct qtree_mem_dqinfo *info, 391884d179dSJan Kara struct dquot *dquot) 392884d179dSJan Kara { 393884d179dSJan Kara int tmp = QT_TREEOFF; 39469a25ee2SKonstantin Khlebnikov 39569a25ee2SKonstantin Khlebnikov #ifdef __QUOTA_QT_PARANOIA 39669a25ee2SKonstantin Khlebnikov if (info->dqi_blocks <= QT_TREEOFF) { 39769a25ee2SKonstantin Khlebnikov quota_error(dquot->dq_sb, "Quota tree root isn't allocated!"); 39869a25ee2SKonstantin Khlebnikov return -EIO; 39969a25ee2SKonstantin Khlebnikov } 40069a25ee2SKonstantin Khlebnikov #endif 401884d179dSJan Kara return do_insert_tree(info, dquot, &tmp, 0); 402884d179dSJan Kara } 403884d179dSJan Kara 404884d179dSJan Kara /* 405268157baSJan Kara * We don't have to be afraid of deadlocks as we never have quotas on quota 406268157baSJan Kara * files... 407884d179dSJan Kara */ 408884d179dSJan Kara int qtree_write_dquot(struct qtree_mem_dqinfo *info, struct dquot *dquot) 409884d179dSJan Kara { 4104c376dcaSEric W. Biederman int type = dquot->dq_id.type; 411884d179dSJan Kara struct super_block *sb = dquot->dq_sb; 412884d179dSJan Kara ssize_t ret; 413*a1e1b2beSJan Kara char *ddquot = kmalloc(info->dqi_entry_size, GFP_KERNEL); 414884d179dSJan Kara 415884d179dSJan Kara if (!ddquot) 416884d179dSJan Kara return -ENOMEM; 417884d179dSJan Kara 418bc8230eeSJan Kara /* dq_off is guarded by dqio_sem */ 419884d179dSJan Kara if (!dquot->dq_off) { 420884d179dSJan Kara ret = dq_insert_tree(info, dquot); 421884d179dSJan Kara if (ret < 0) { 422fb5ffb0eSJiaying Zhang quota_error(sb, "Error %zd occurred while creating " 423fb5ffb0eSJiaying Zhang "quota", ret); 424d26ac1a8SJan Kara kfree(ddquot); 425884d179dSJan Kara return ret; 426884d179dSJan Kara } 427884d179dSJan Kara } 4287b9ca4c6SJan Kara spin_lock(&dquot->dq_dqb_lock); 429884d179dSJan Kara info->dqi_ops->mem2disk_dqblk(ddquot, dquot); 4307b9ca4c6SJan Kara spin_unlock(&dquot->dq_dqb_lock); 431d26ac1a8SJan Kara ret = sb->s_op->quota_write(sb, type, ddquot, info->dqi_entry_size, 432d26ac1a8SJan Kara dquot->dq_off); 433884d179dSJan Kara if (ret != info->dqi_entry_size) { 434fb5ffb0eSJiaying Zhang quota_error(sb, "dquota write failed"); 435884d179dSJan Kara if (ret >= 0) 436884d179dSJan Kara ret = -ENOSPC; 437884d179dSJan Kara } else { 438884d179dSJan Kara ret = 0; 439884d179dSJan Kara } 440dde95888SDmitry Monakhov dqstats_inc(DQST_WRITES); 441d26ac1a8SJan Kara kfree(ddquot); 442884d179dSJan Kara 443884d179dSJan Kara return ret; 444884d179dSJan Kara } 445884d179dSJan Kara EXPORT_SYMBOL(qtree_write_dquot); 446884d179dSJan Kara 447884d179dSJan Kara /* Free dquot entry in data block */ 448884d179dSJan Kara static int free_dqentry(struct qtree_mem_dqinfo *info, struct dquot *dquot, 449884d179dSJan Kara uint blk) 450884d179dSJan Kara { 451884d179dSJan Kara struct qt_disk_dqdbheader *dh; 452*a1e1b2beSJan Kara char *buf = kmalloc(info->dqi_usable_bs, GFP_KERNEL); 453884d179dSJan Kara int ret = 0; 454884d179dSJan Kara 455884d179dSJan Kara if (!buf) 456884d179dSJan Kara return -ENOMEM; 457884d179dSJan Kara if (dquot->dq_off >> info->dqi_blocksize_bits != blk) { 458fb5ffb0eSJiaying Zhang quota_error(dquot->dq_sb, "Quota structure has offset to " 459fb5ffb0eSJiaying Zhang "other block (%u) than it should (%u)", blk, 460884d179dSJan Kara (uint)(dquot->dq_off >> info->dqi_blocksize_bits)); 461d0e36a62SZhang Yi ret = -EIO; 462884d179dSJan Kara goto out_buf; 463884d179dSJan Kara } 464884d179dSJan Kara ret = read_blk(info, blk, buf); 465884d179dSJan Kara if (ret < 0) { 466fb5ffb0eSJiaying Zhang quota_error(dquot->dq_sb, "Can't read quota data block %u", 467fb5ffb0eSJiaying Zhang blk); 468884d179dSJan Kara goto out_buf; 469884d179dSJan Kara } 470884d179dSJan Kara dh = (struct qt_disk_dqdbheader *)buf; 4716c8ea8b8SZhihao Cheng ret = check_dquot_block_header(info, dh); 4726c8ea8b8SZhihao Cheng if (ret) 4736c8ea8b8SZhihao Cheng goto out_buf; 474884d179dSJan Kara le16_add_cpu(&dh->dqdh_entries, -1); 475884d179dSJan Kara if (!le16_to_cpu(dh->dqdh_entries)) { /* Block got free? */ 476884d179dSJan Kara ret = remove_free_dqentry(info, buf, blk); 477884d179dSJan Kara if (ret >= 0) 478884d179dSJan Kara ret = put_free_dqblk(info, buf, blk); 479884d179dSJan Kara if (ret < 0) { 480fb5ffb0eSJiaying Zhang quota_error(dquot->dq_sb, "Can't move quota data block " 481fb5ffb0eSJiaying Zhang "(%u) to free list", blk); 482884d179dSJan Kara goto out_buf; 483884d179dSJan Kara } 484884d179dSJan Kara } else { 485884d179dSJan Kara memset(buf + 486884d179dSJan Kara (dquot->dq_off & ((1 << info->dqi_blocksize_bits) - 1)), 487884d179dSJan Kara 0, info->dqi_entry_size); 488884d179dSJan Kara if (le16_to_cpu(dh->dqdh_entries) == 489884d179dSJan Kara qtree_dqstr_in_blk(info) - 1) { 490884d179dSJan Kara /* Insert will write block itself */ 491884d179dSJan Kara ret = insert_free_dqentry(info, buf, blk); 492884d179dSJan Kara if (ret < 0) { 493fb5ffb0eSJiaying Zhang quota_error(dquot->dq_sb, "Can't insert quota " 494fb5ffb0eSJiaying Zhang "data block (%u) to free entry list", blk); 495884d179dSJan Kara goto out_buf; 496884d179dSJan Kara } 497884d179dSJan Kara } else { 498884d179dSJan Kara ret = write_blk(info, blk, buf); 499884d179dSJan Kara if (ret < 0) { 500fb5ffb0eSJiaying Zhang quota_error(dquot->dq_sb, "Can't write quota " 501fb5ffb0eSJiaying Zhang "data block %u", blk); 502884d179dSJan Kara goto out_buf; 503884d179dSJan Kara } 504884d179dSJan Kara } 505884d179dSJan Kara } 506884d179dSJan Kara dquot->dq_off = 0; /* Quota is now unattached */ 507884d179dSJan Kara out_buf: 508d26ac1a8SJan Kara kfree(buf); 509884d179dSJan Kara return ret; 510884d179dSJan Kara } 511884d179dSJan Kara 512884d179dSJan Kara /* Remove reference to dquot from tree */ 513884d179dSJan Kara static int remove_tree(struct qtree_mem_dqinfo *info, struct dquot *dquot, 514884d179dSJan Kara uint *blk, int depth) 515884d179dSJan Kara { 516*a1e1b2beSJan Kara char *buf = kmalloc(info->dqi_usable_bs, GFP_KERNEL); 517884d179dSJan Kara int ret = 0; 518884d179dSJan Kara uint newblk; 519884d179dSJan Kara __le32 *ref = (__le32 *)buf; 520884d179dSJan Kara 521884d179dSJan Kara if (!buf) 522884d179dSJan Kara return -ENOMEM; 523884d179dSJan Kara ret = read_blk(info, *blk, buf); 524884d179dSJan Kara if (ret < 0) { 525055adcbdSJoe Perches quota_error(dquot->dq_sb, "Can't read quota data block %u", 526055adcbdSJoe Perches *blk); 527884d179dSJan Kara goto out_buf; 528884d179dSJan Kara } 529884d179dSJan Kara newblk = le32_to_cpu(ref[get_index(info, dquot->dq_id, depth)]); 5303fc61e0eSZhihao Cheng ret = do_check_range(dquot->dq_sb, "block", newblk, QT_TREEOFF, 5313fc61e0eSZhihao Cheng info->dqi_blocks - 1); 5323fc61e0eSZhihao Cheng if (ret) 5339bf3d203SZhang Yi goto out_buf; 5349bf3d203SZhang Yi 535884d179dSJan Kara if (depth == info->dqi_qtree_depth - 1) { 536884d179dSJan Kara ret = free_dqentry(info, dquot, newblk); 537884d179dSJan Kara newblk = 0; 538884d179dSJan Kara } else { 539884d179dSJan Kara ret = remove_tree(info, dquot, &newblk, depth+1); 540884d179dSJan Kara } 541884d179dSJan Kara if (ret >= 0 && !newblk) { 542884d179dSJan Kara int i; 543884d179dSJan Kara ref[get_index(info, dquot->dq_id, depth)] = cpu_to_le32(0); 544884d179dSJan Kara /* Block got empty? */ 545d26ac1a8SJan Kara for (i = 0; i < (info->dqi_usable_bs >> 2) && !ref[i]; i++) 546d26ac1a8SJan Kara ; 547884d179dSJan Kara /* Don't put the root block into the free block list */ 548884d179dSJan Kara if (i == (info->dqi_usable_bs >> 2) 549884d179dSJan Kara && *blk != QT_TREEOFF) { 550884d179dSJan Kara put_free_dqblk(info, buf, *blk); 551884d179dSJan Kara *blk = 0; 552884d179dSJan Kara } else { 553884d179dSJan Kara ret = write_blk(info, *blk, buf); 554884d179dSJan Kara if (ret < 0) 555055adcbdSJoe Perches quota_error(dquot->dq_sb, 556055adcbdSJoe Perches "Can't write quota tree block %u", 557055adcbdSJoe Perches *blk); 558884d179dSJan Kara } 559884d179dSJan Kara } 560884d179dSJan Kara out_buf: 561d26ac1a8SJan Kara kfree(buf); 562884d179dSJan Kara return ret; 563884d179dSJan Kara } 564884d179dSJan Kara 565884d179dSJan Kara /* Delete dquot from tree */ 566884d179dSJan Kara int qtree_delete_dquot(struct qtree_mem_dqinfo *info, struct dquot *dquot) 567884d179dSJan Kara { 568884d179dSJan Kara uint tmp = QT_TREEOFF; 569884d179dSJan Kara 570884d179dSJan Kara if (!dquot->dq_off) /* Even not allocated? */ 571884d179dSJan Kara return 0; 572884d179dSJan Kara return remove_tree(info, dquot, &tmp, 0); 573884d179dSJan Kara } 574884d179dSJan Kara EXPORT_SYMBOL(qtree_delete_dquot); 575884d179dSJan Kara 576884d179dSJan Kara /* Find entry in block */ 577884d179dSJan Kara static loff_t find_block_dqentry(struct qtree_mem_dqinfo *info, 578884d179dSJan Kara struct dquot *dquot, uint blk) 579884d179dSJan Kara { 580*a1e1b2beSJan Kara char *buf = kmalloc(info->dqi_usable_bs, GFP_KERNEL); 581884d179dSJan Kara loff_t ret = 0; 582884d179dSJan Kara int i; 583884d179dSJan Kara char *ddquot; 584884d179dSJan Kara 585884d179dSJan Kara if (!buf) 586884d179dSJan Kara return -ENOMEM; 587884d179dSJan Kara ret = read_blk(info, blk, buf); 588884d179dSJan Kara if (ret < 0) { 589fb5ffb0eSJiaying Zhang quota_error(dquot->dq_sb, "Can't read quota tree " 590fb5ffb0eSJiaying Zhang "block %u", blk); 591884d179dSJan Kara goto out_buf; 592884d179dSJan Kara } 593268157baSJan Kara ddquot = buf + sizeof(struct qt_disk_dqdbheader); 594268157baSJan Kara for (i = 0; i < qtree_dqstr_in_blk(info); i++) { 595268157baSJan Kara if (info->dqi_ops->is_id(ddquot, dquot)) 596268157baSJan Kara break; 597268157baSJan Kara ddquot += info->dqi_entry_size; 598268157baSJan Kara } 599884d179dSJan Kara if (i == qtree_dqstr_in_blk(info)) { 6004c376dcaSEric W. Biederman quota_error(dquot->dq_sb, 6014c376dcaSEric W. Biederman "Quota for id %u referenced but not present", 6024c376dcaSEric W. Biederman from_kqid(&init_user_ns, dquot->dq_id)); 603884d179dSJan Kara ret = -EIO; 604884d179dSJan Kara goto out_buf; 605884d179dSJan Kara } else { 60610f04d40SJan Kara ret = ((loff_t)blk << info->dqi_blocksize_bits) + sizeof(struct 607884d179dSJan Kara qt_disk_dqdbheader) + i * info->dqi_entry_size; 608884d179dSJan Kara } 609884d179dSJan Kara out_buf: 610d26ac1a8SJan Kara kfree(buf); 611884d179dSJan Kara return ret; 612884d179dSJan Kara } 613884d179dSJan Kara 614884d179dSJan Kara /* Find entry for given id in the tree */ 615884d179dSJan Kara static loff_t find_tree_dqentry(struct qtree_mem_dqinfo *info, 616884d179dSJan Kara struct dquot *dquot, uint blk, int depth) 617884d179dSJan Kara { 618*a1e1b2beSJan Kara char *buf = kmalloc(info->dqi_usable_bs, GFP_KERNEL); 619884d179dSJan Kara loff_t ret = 0; 620884d179dSJan Kara __le32 *ref = (__le32 *)buf; 621884d179dSJan Kara 622884d179dSJan Kara if (!buf) 623884d179dSJan Kara return -ENOMEM; 624884d179dSJan Kara ret = read_blk(info, blk, buf); 625884d179dSJan Kara if (ret < 0) { 626fb5ffb0eSJiaying Zhang quota_error(dquot->dq_sb, "Can't read quota tree block %u", 627fb5ffb0eSJiaying Zhang blk); 628884d179dSJan Kara goto out_buf; 629884d179dSJan Kara } 630884d179dSJan Kara ret = 0; 631884d179dSJan Kara blk = le32_to_cpu(ref[get_index(info, dquot->dq_id, depth)]); 632884d179dSJan Kara if (!blk) /* No reference? */ 633884d179dSJan Kara goto out_buf; 6343fc61e0eSZhihao Cheng ret = do_check_range(dquot->dq_sb, "block", blk, QT_TREEOFF, 6353fc61e0eSZhihao Cheng info->dqi_blocks - 1); 6363fc61e0eSZhihao Cheng if (ret) 6379bf3d203SZhang Yi goto out_buf; 6389bf3d203SZhang Yi 639884d179dSJan Kara if (depth < info->dqi_qtree_depth - 1) 640884d179dSJan Kara ret = find_tree_dqentry(info, dquot, blk, depth+1); 641884d179dSJan Kara else 642884d179dSJan Kara ret = find_block_dqentry(info, dquot, blk); 643884d179dSJan Kara out_buf: 644d26ac1a8SJan Kara kfree(buf); 645884d179dSJan Kara return ret; 646884d179dSJan Kara } 647884d179dSJan Kara 648884d179dSJan Kara /* Find entry for given id in the tree - wrapper function */ 649884d179dSJan Kara static inline loff_t find_dqentry(struct qtree_mem_dqinfo *info, 650884d179dSJan Kara struct dquot *dquot) 651884d179dSJan Kara { 652884d179dSJan Kara return find_tree_dqentry(info, dquot, QT_TREEOFF, 0); 653884d179dSJan Kara } 654884d179dSJan Kara 655884d179dSJan Kara int qtree_read_dquot(struct qtree_mem_dqinfo *info, struct dquot *dquot) 656884d179dSJan Kara { 6574c376dcaSEric W. Biederman int type = dquot->dq_id.type; 658884d179dSJan Kara struct super_block *sb = dquot->dq_sb; 659884d179dSJan Kara loff_t offset; 660d26ac1a8SJan Kara char *ddquot; 661884d179dSJan Kara int ret = 0; 662884d179dSJan Kara 663884d179dSJan Kara #ifdef __QUOTA_QT_PARANOIA 664884d179dSJan Kara /* Invalidated quota? */ 665884d179dSJan Kara if (!sb_dqopt(dquot->dq_sb)->files[type]) { 666fb5ffb0eSJiaying Zhang quota_error(sb, "Quota invalidated while reading!"); 667884d179dSJan Kara return -EIO; 668884d179dSJan Kara } 669884d179dSJan Kara #endif 670884d179dSJan Kara /* Do we know offset of the dquot entry in the quota file? */ 671884d179dSJan Kara if (!dquot->dq_off) { 672884d179dSJan Kara offset = find_dqentry(info, dquot); 673884d179dSJan Kara if (offset <= 0) { /* Entry not present? */ 674884d179dSJan Kara if (offset < 0) 675fb5ffb0eSJiaying Zhang quota_error(sb,"Can't read quota structure " 6764c376dcaSEric W. Biederman "for id %u", 6774c376dcaSEric W. Biederman from_kqid(&init_user_ns, 6784c376dcaSEric W. Biederman dquot->dq_id)); 679884d179dSJan Kara dquot->dq_off = 0; 680884d179dSJan Kara set_bit(DQ_FAKE_B, &dquot->dq_flags); 681884d179dSJan Kara memset(&dquot->dq_dqb, 0, sizeof(struct mem_dqblk)); 682884d179dSJan Kara ret = offset; 683884d179dSJan Kara goto out; 684884d179dSJan Kara } 685884d179dSJan Kara dquot->dq_off = offset; 686884d179dSJan Kara } 687*a1e1b2beSJan Kara ddquot = kmalloc(info->dqi_entry_size, GFP_KERNEL); 688884d179dSJan Kara if (!ddquot) 689884d179dSJan Kara return -ENOMEM; 690d26ac1a8SJan Kara ret = sb->s_op->quota_read(sb, type, ddquot, info->dqi_entry_size, 691d26ac1a8SJan Kara dquot->dq_off); 692884d179dSJan Kara if (ret != info->dqi_entry_size) { 693884d179dSJan Kara if (ret >= 0) 694884d179dSJan Kara ret = -EIO; 695fb5ffb0eSJiaying Zhang quota_error(sb, "Error while reading quota structure for id %u", 6964c376dcaSEric W. Biederman from_kqid(&init_user_ns, dquot->dq_id)); 697884d179dSJan Kara set_bit(DQ_FAKE_B, &dquot->dq_flags); 698884d179dSJan Kara memset(&dquot->dq_dqb, 0, sizeof(struct mem_dqblk)); 699d26ac1a8SJan Kara kfree(ddquot); 700884d179dSJan Kara goto out; 701884d179dSJan Kara } 7027b9ca4c6SJan Kara spin_lock(&dquot->dq_dqb_lock); 703884d179dSJan Kara info->dqi_ops->disk2mem_dqblk(dquot, ddquot); 704884d179dSJan Kara if (!dquot->dq_dqb.dqb_bhardlimit && 705884d179dSJan Kara !dquot->dq_dqb.dqb_bsoftlimit && 706884d179dSJan Kara !dquot->dq_dqb.dqb_ihardlimit && 707884d179dSJan Kara !dquot->dq_dqb.dqb_isoftlimit) 708884d179dSJan Kara set_bit(DQ_FAKE_B, &dquot->dq_flags); 7097b9ca4c6SJan Kara spin_unlock(&dquot->dq_dqb_lock); 710d26ac1a8SJan Kara kfree(ddquot); 711884d179dSJan Kara out: 712dde95888SDmitry Monakhov dqstats_inc(DQST_READS); 713884d179dSJan Kara return ret; 714884d179dSJan Kara } 715884d179dSJan Kara EXPORT_SYMBOL(qtree_read_dquot); 716884d179dSJan Kara 717884d179dSJan Kara /* Check whether dquot should not be deleted. We know we are 718884d179dSJan Kara * the only one operating on dquot (thanks to dq_lock) */ 719884d179dSJan Kara int qtree_release_dquot(struct qtree_mem_dqinfo *info, struct dquot *dquot) 720884d179dSJan Kara { 721268157baSJan Kara if (test_bit(DQ_FAKE_B, &dquot->dq_flags) && 722268157baSJan Kara !(dquot->dq_dqb.dqb_curinodes | dquot->dq_dqb.dqb_curspace)) 723884d179dSJan Kara return qtree_delete_dquot(info, dquot); 724884d179dSJan Kara return 0; 725884d179dSJan Kara } 726884d179dSJan Kara EXPORT_SYMBOL(qtree_release_dquot); 7270066373dSJan Kara 7280066373dSJan Kara static int find_next_id(struct qtree_mem_dqinfo *info, qid_t *id, 7290066373dSJan Kara unsigned int blk, int depth) 7300066373dSJan Kara { 731*a1e1b2beSJan Kara char *buf = kmalloc(info->dqi_usable_bs, GFP_KERNEL); 7320066373dSJan Kara __le32 *ref = (__le32 *)buf; 7330066373dSJan Kara ssize_t ret; 7340066373dSJan Kara unsigned int epb = info->dqi_usable_bs >> 2; 7350066373dSJan Kara unsigned int level_inc = 1; 7360066373dSJan Kara int i; 7370066373dSJan Kara 7380066373dSJan Kara if (!buf) 7390066373dSJan Kara return -ENOMEM; 7400066373dSJan Kara 7410066373dSJan Kara for (i = depth; i < info->dqi_qtree_depth - 1; i++) 7420066373dSJan Kara level_inc *= epb; 7430066373dSJan Kara 7440066373dSJan Kara ret = read_blk(info, blk, buf); 7450066373dSJan Kara if (ret < 0) { 7460066373dSJan Kara quota_error(info->dqi_sb, 7470066373dSJan Kara "Can't read quota tree block %u", blk); 7480066373dSJan Kara goto out_buf; 7490066373dSJan Kara } 7500066373dSJan Kara for (i = __get_index(info, *id, depth); i < epb; i++) { 751191249f7SZhihao Cheng uint blk_no = le32_to_cpu(ref[i]); 752191249f7SZhihao Cheng 753191249f7SZhihao Cheng if (blk_no == 0) { 7540066373dSJan Kara *id += level_inc; 7550066373dSJan Kara continue; 7560066373dSJan Kara } 757191249f7SZhihao Cheng ret = do_check_range(info->dqi_sb, "block", blk_no, 0, 758191249f7SZhihao Cheng info->dqi_blocks - 1); 759191249f7SZhihao Cheng if (ret) 760191249f7SZhihao Cheng goto out_buf; 7610066373dSJan Kara if (depth == info->dqi_qtree_depth - 1) { 7620066373dSJan Kara ret = 0; 7630066373dSJan Kara goto out_buf; 7640066373dSJan Kara } 765191249f7SZhihao Cheng ret = find_next_id(info, id, blk_no, depth + 1); 7660066373dSJan Kara if (ret != -ENOENT) 7670066373dSJan Kara break; 7680066373dSJan Kara } 7690066373dSJan Kara if (i == epb) { 7700066373dSJan Kara ret = -ENOENT; 7710066373dSJan Kara goto out_buf; 7720066373dSJan Kara } 7730066373dSJan Kara out_buf: 7740066373dSJan Kara kfree(buf); 7750066373dSJan Kara return ret; 7760066373dSJan Kara } 7770066373dSJan Kara 7780066373dSJan Kara int qtree_get_next_id(struct qtree_mem_dqinfo *info, struct kqid *qid) 7790066373dSJan Kara { 7800066373dSJan Kara qid_t id = from_kqid(&init_user_ns, *qid); 7810066373dSJan Kara int ret; 7820066373dSJan Kara 7830066373dSJan Kara ret = find_next_id(info, &id, QT_TREEOFF, 0); 7840066373dSJan Kara if (ret < 0) 7850066373dSJan Kara return ret; 7860066373dSJan Kara *qid = make_kqid(&init_user_ns, qid->type, id); 7870066373dSJan Kara return 0; 7880066373dSJan Kara } 7890066373dSJan Kara EXPORT_SYMBOL(qtree_get_next_id); 790