1884d179dSJan Kara /* 2884d179dSJan Kara * vfsv0 quota IO operations on file 3884d179dSJan Kara */ 4884d179dSJan Kara 5884d179dSJan Kara #include <linux/errno.h> 6884d179dSJan Kara #include <linux/fs.h> 7884d179dSJan Kara #include <linux/mount.h> 8884d179dSJan Kara #include <linux/dqblk_v2.h> 9884d179dSJan Kara #include <linux/kernel.h> 10884d179dSJan Kara #include <linux/init.h> 11884d179dSJan Kara #include <linux/module.h> 12884d179dSJan Kara #include <linux/slab.h> 13884d179dSJan Kara #include <linux/quotaops.h> 14884d179dSJan Kara 15884d179dSJan Kara #include <asm/byteorder.h> 16884d179dSJan Kara 17884d179dSJan Kara #include "quota_tree.h" 18884d179dSJan Kara 19884d179dSJan Kara MODULE_AUTHOR("Jan Kara"); 20884d179dSJan Kara MODULE_DESCRIPTION("Quota trie support"); 21884d179dSJan Kara MODULE_LICENSE("GPL"); 22884d179dSJan Kara 23884d179dSJan Kara #define __QUOTA_QT_PARANOIA 24884d179dSJan Kara 25*4c376dcaSEric W. Biederman static int get_index(struct qtree_mem_dqinfo *info, struct kqid qid, int depth) 26884d179dSJan Kara { 27884d179dSJan Kara unsigned int epb = info->dqi_usable_bs >> 2; 28*4c376dcaSEric W. Biederman qid_t id = from_kqid(&init_user_ns, qid); 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 36884d179dSJan Kara /* Number of entries in one blocks */ 377a2435d8SJan Kara static int qtree_dqstr_in_blk(struct qtree_mem_dqinfo *info) 38884d179dSJan Kara { 39884d179dSJan Kara return (info->dqi_usable_bs - sizeof(struct qt_disk_dqdbheader)) 40884d179dSJan Kara / info->dqi_entry_size; 41884d179dSJan Kara } 42884d179dSJan Kara 43d26ac1a8SJan Kara static char *getdqbuf(size_t size) 44884d179dSJan Kara { 45d26ac1a8SJan Kara char *buf = kmalloc(size, GFP_NOFS); 46884d179dSJan Kara if (!buf) 47268157baSJan Kara printk(KERN_WARNING 48268157baSJan Kara "VFS: Not enough memory for quota buffers.\n"); 49884d179dSJan Kara return buf; 50884d179dSJan Kara } 51884d179dSJan Kara 527a2435d8SJan Kara static ssize_t read_blk(struct qtree_mem_dqinfo *info, uint blk, char *buf) 53884d179dSJan Kara { 54884d179dSJan Kara struct super_block *sb = info->dqi_sb; 55884d179dSJan Kara 56884d179dSJan Kara memset(buf, 0, info->dqi_usable_bs); 57d26ac1a8SJan Kara return sb->s_op->quota_read(sb, info->dqi_type, buf, 58884d179dSJan Kara info->dqi_usable_bs, blk << info->dqi_blocksize_bits); 59884d179dSJan Kara } 60884d179dSJan Kara 617a2435d8SJan Kara static ssize_t write_blk(struct qtree_mem_dqinfo *info, uint blk, char *buf) 62884d179dSJan Kara { 63884d179dSJan Kara struct super_block *sb = info->dqi_sb; 641907131bSJiaying Zhang ssize_t ret; 65884d179dSJan Kara 661907131bSJiaying Zhang ret = sb->s_op->quota_write(sb, info->dqi_type, buf, 67884d179dSJan Kara info->dqi_usable_bs, blk << info->dqi_blocksize_bits); 681907131bSJiaying Zhang if (ret != info->dqi_usable_bs) { 69fb5ffb0eSJiaying Zhang quota_error(sb, "dquota write failed"); 701907131bSJiaying Zhang if (ret >= 0) 711907131bSJiaying Zhang ret = -EIO; 721907131bSJiaying Zhang } 731907131bSJiaying Zhang return ret; 74884d179dSJan Kara } 75884d179dSJan Kara 76884d179dSJan Kara /* Remove empty block from list and return it */ 77884d179dSJan Kara static int get_free_dqblk(struct qtree_mem_dqinfo *info) 78884d179dSJan Kara { 79d26ac1a8SJan Kara char *buf = getdqbuf(info->dqi_usable_bs); 80884d179dSJan Kara struct qt_disk_dqdbheader *dh = (struct qt_disk_dqdbheader *)buf; 81884d179dSJan Kara int ret, blk; 82884d179dSJan Kara 83884d179dSJan Kara if (!buf) 84884d179dSJan Kara return -ENOMEM; 85884d179dSJan Kara if (info->dqi_free_blk) { 86884d179dSJan Kara blk = info->dqi_free_blk; 87884d179dSJan Kara ret = read_blk(info, blk, buf); 88884d179dSJan Kara if (ret < 0) 89884d179dSJan Kara goto out_buf; 90884d179dSJan Kara info->dqi_free_blk = le32_to_cpu(dh->dqdh_next_free); 91884d179dSJan Kara } 92884d179dSJan Kara else { 93884d179dSJan Kara memset(buf, 0, info->dqi_usable_bs); 94884d179dSJan Kara /* Assure block allocation... */ 95884d179dSJan Kara ret = write_blk(info, info->dqi_blocks, buf); 96884d179dSJan Kara if (ret < 0) 97884d179dSJan Kara goto out_buf; 98884d179dSJan Kara blk = info->dqi_blocks++; 99884d179dSJan Kara } 100884d179dSJan Kara mark_info_dirty(info->dqi_sb, info->dqi_type); 101884d179dSJan Kara ret = blk; 102884d179dSJan Kara out_buf: 103d26ac1a8SJan Kara kfree(buf); 104884d179dSJan Kara return ret; 105884d179dSJan Kara } 106884d179dSJan Kara 107884d179dSJan Kara /* Insert empty block to the list */ 108d26ac1a8SJan Kara static int put_free_dqblk(struct qtree_mem_dqinfo *info, char *buf, uint blk) 109884d179dSJan Kara { 110884d179dSJan Kara struct qt_disk_dqdbheader *dh = (struct qt_disk_dqdbheader *)buf; 111884d179dSJan Kara int err; 112884d179dSJan Kara 113884d179dSJan Kara dh->dqdh_next_free = cpu_to_le32(info->dqi_free_blk); 114884d179dSJan Kara dh->dqdh_prev_free = cpu_to_le32(0); 115884d179dSJan Kara dh->dqdh_entries = cpu_to_le16(0); 116884d179dSJan Kara err = write_blk(info, blk, buf); 117884d179dSJan Kara if (err < 0) 118884d179dSJan Kara return err; 119884d179dSJan Kara info->dqi_free_blk = blk; 120884d179dSJan Kara mark_info_dirty(info->dqi_sb, info->dqi_type); 121884d179dSJan Kara return 0; 122884d179dSJan Kara } 123884d179dSJan Kara 124884d179dSJan Kara /* Remove given block from the list of blocks with free entries */ 125268157baSJan Kara static int remove_free_dqentry(struct qtree_mem_dqinfo *info, char *buf, 126268157baSJan Kara uint blk) 127884d179dSJan Kara { 128d26ac1a8SJan Kara char *tmpbuf = getdqbuf(info->dqi_usable_bs); 129884d179dSJan Kara struct qt_disk_dqdbheader *dh = (struct qt_disk_dqdbheader *)buf; 130884d179dSJan Kara uint nextblk = le32_to_cpu(dh->dqdh_next_free); 131884d179dSJan Kara uint prevblk = le32_to_cpu(dh->dqdh_prev_free); 132884d179dSJan Kara int err; 133884d179dSJan Kara 134884d179dSJan Kara if (!tmpbuf) 135884d179dSJan Kara return -ENOMEM; 136884d179dSJan Kara if (nextblk) { 137884d179dSJan Kara err = read_blk(info, nextblk, tmpbuf); 138884d179dSJan Kara if (err < 0) 139884d179dSJan Kara goto out_buf; 140884d179dSJan Kara ((struct qt_disk_dqdbheader *)tmpbuf)->dqdh_prev_free = 141884d179dSJan Kara dh->dqdh_prev_free; 142884d179dSJan Kara err = write_blk(info, nextblk, tmpbuf); 143884d179dSJan Kara if (err < 0) 144884d179dSJan Kara goto out_buf; 145884d179dSJan Kara } 146884d179dSJan Kara if (prevblk) { 147884d179dSJan Kara err = read_blk(info, prevblk, tmpbuf); 148884d179dSJan Kara if (err < 0) 149884d179dSJan Kara goto out_buf; 150884d179dSJan Kara ((struct qt_disk_dqdbheader *)tmpbuf)->dqdh_next_free = 151884d179dSJan Kara dh->dqdh_next_free; 152884d179dSJan Kara err = write_blk(info, prevblk, tmpbuf); 153884d179dSJan Kara if (err < 0) 154884d179dSJan Kara goto out_buf; 155884d179dSJan Kara } else { 156884d179dSJan Kara info->dqi_free_entry = nextblk; 157884d179dSJan Kara mark_info_dirty(info->dqi_sb, info->dqi_type); 158884d179dSJan Kara } 159d26ac1a8SJan Kara kfree(tmpbuf); 160884d179dSJan Kara dh->dqdh_next_free = dh->dqdh_prev_free = cpu_to_le32(0); 161884d179dSJan Kara /* No matter whether write succeeds block is out of list */ 162884d179dSJan Kara if (write_blk(info, blk, buf) < 0) 163fb5ffb0eSJiaying Zhang quota_error(info->dqi_sb, "Can't write block (%u) " 164fb5ffb0eSJiaying Zhang "with free entries", blk); 165884d179dSJan Kara return 0; 166884d179dSJan Kara out_buf: 167d26ac1a8SJan Kara kfree(tmpbuf); 168884d179dSJan Kara return err; 169884d179dSJan Kara } 170884d179dSJan Kara 171884d179dSJan Kara /* Insert given block to the beginning of list with free entries */ 172268157baSJan Kara static int insert_free_dqentry(struct qtree_mem_dqinfo *info, char *buf, 173268157baSJan Kara uint blk) 174884d179dSJan Kara { 175d26ac1a8SJan Kara char *tmpbuf = getdqbuf(info->dqi_usable_bs); 176884d179dSJan Kara struct qt_disk_dqdbheader *dh = (struct qt_disk_dqdbheader *)buf; 177884d179dSJan Kara int err; 178884d179dSJan Kara 179884d179dSJan Kara if (!tmpbuf) 180884d179dSJan Kara return -ENOMEM; 181884d179dSJan Kara dh->dqdh_next_free = cpu_to_le32(info->dqi_free_entry); 182884d179dSJan Kara dh->dqdh_prev_free = cpu_to_le32(0); 183884d179dSJan Kara err = write_blk(info, blk, buf); 184884d179dSJan Kara if (err < 0) 185884d179dSJan Kara goto out_buf; 186884d179dSJan Kara if (info->dqi_free_entry) { 187884d179dSJan Kara err = read_blk(info, info->dqi_free_entry, tmpbuf); 188884d179dSJan Kara if (err < 0) 189884d179dSJan Kara goto out_buf; 190884d179dSJan Kara ((struct qt_disk_dqdbheader *)tmpbuf)->dqdh_prev_free = 191884d179dSJan Kara cpu_to_le32(blk); 192884d179dSJan Kara err = write_blk(info, info->dqi_free_entry, tmpbuf); 193884d179dSJan Kara if (err < 0) 194884d179dSJan Kara goto out_buf; 195884d179dSJan Kara } 196d26ac1a8SJan Kara kfree(tmpbuf); 197884d179dSJan Kara info->dqi_free_entry = blk; 198884d179dSJan Kara mark_info_dirty(info->dqi_sb, info->dqi_type); 199884d179dSJan Kara return 0; 200884d179dSJan Kara out_buf: 201d26ac1a8SJan Kara kfree(tmpbuf); 202884d179dSJan Kara return err; 203884d179dSJan Kara } 204884d179dSJan Kara 205884d179dSJan Kara /* Is the entry in the block free? */ 206884d179dSJan Kara int qtree_entry_unused(struct qtree_mem_dqinfo *info, char *disk) 207884d179dSJan Kara { 208884d179dSJan Kara int i; 209884d179dSJan Kara 210884d179dSJan Kara for (i = 0; i < info->dqi_entry_size; i++) 211884d179dSJan Kara if (disk[i]) 212884d179dSJan Kara return 0; 213884d179dSJan Kara return 1; 214884d179dSJan Kara } 215884d179dSJan Kara EXPORT_SYMBOL(qtree_entry_unused); 216884d179dSJan Kara 217884d179dSJan Kara /* Find space for dquot */ 218884d179dSJan Kara static uint find_free_dqentry(struct qtree_mem_dqinfo *info, 219884d179dSJan Kara struct dquot *dquot, int *err) 220884d179dSJan Kara { 221884d179dSJan Kara uint blk, i; 222884d179dSJan Kara struct qt_disk_dqdbheader *dh; 223d26ac1a8SJan Kara char *buf = getdqbuf(info->dqi_usable_bs); 224884d179dSJan Kara char *ddquot; 225884d179dSJan Kara 226884d179dSJan Kara *err = 0; 227884d179dSJan Kara if (!buf) { 228884d179dSJan Kara *err = -ENOMEM; 229884d179dSJan Kara return 0; 230884d179dSJan Kara } 231884d179dSJan Kara dh = (struct qt_disk_dqdbheader *)buf; 232884d179dSJan Kara if (info->dqi_free_entry) { 233884d179dSJan Kara blk = info->dqi_free_entry; 234884d179dSJan Kara *err = read_blk(info, blk, buf); 235884d179dSJan Kara if (*err < 0) 236884d179dSJan Kara goto out_buf; 237884d179dSJan Kara } else { 238884d179dSJan Kara blk = get_free_dqblk(info); 239884d179dSJan Kara if ((int)blk < 0) { 240884d179dSJan Kara *err = blk; 241d26ac1a8SJan Kara kfree(buf); 242884d179dSJan Kara return 0; 243884d179dSJan Kara } 244884d179dSJan Kara memset(buf, 0, info->dqi_usable_bs); 245268157baSJan Kara /* This is enough as the block is already zeroed and the entry 246268157baSJan Kara * list is empty... */ 247884d179dSJan Kara info->dqi_free_entry = blk; 248*4c376dcaSEric W. Biederman mark_info_dirty(dquot->dq_sb, dquot->dq_id.type); 249884d179dSJan Kara } 250884d179dSJan Kara /* Block will be full? */ 251884d179dSJan Kara if (le16_to_cpu(dh->dqdh_entries) + 1 >= qtree_dqstr_in_blk(info)) { 252884d179dSJan Kara *err = remove_free_dqentry(info, buf, blk); 253884d179dSJan Kara if (*err < 0) { 254fb5ffb0eSJiaying Zhang quota_error(dquot->dq_sb, "Can't remove block (%u) " 255fb5ffb0eSJiaying Zhang "from entry free list", blk); 256884d179dSJan Kara goto out_buf; 257884d179dSJan Kara } 258884d179dSJan Kara } 259884d179dSJan Kara le16_add_cpu(&dh->dqdh_entries, 1); 260884d179dSJan Kara /* Find free structure in block */ 261268157baSJan Kara ddquot = buf + sizeof(struct qt_disk_dqdbheader); 262268157baSJan Kara for (i = 0; i < qtree_dqstr_in_blk(info); i++) { 263268157baSJan Kara if (qtree_entry_unused(info, ddquot)) 264268157baSJan Kara break; 265268157baSJan Kara ddquot += info->dqi_entry_size; 266268157baSJan Kara } 267884d179dSJan Kara #ifdef __QUOTA_QT_PARANOIA 268884d179dSJan Kara if (i == qtree_dqstr_in_blk(info)) { 269fb5ffb0eSJiaying Zhang quota_error(dquot->dq_sb, "Data block full but it shouldn't"); 270884d179dSJan Kara *err = -EIO; 271884d179dSJan Kara goto out_buf; 272884d179dSJan Kara } 273884d179dSJan Kara #endif 274884d179dSJan Kara *err = write_blk(info, blk, buf); 275884d179dSJan Kara if (*err < 0) { 276fb5ffb0eSJiaying Zhang quota_error(dquot->dq_sb, "Can't write quota data block %u", 277fb5ffb0eSJiaying Zhang blk); 278884d179dSJan Kara goto out_buf; 279884d179dSJan Kara } 280884d179dSJan Kara dquot->dq_off = (blk << info->dqi_blocksize_bits) + 281884d179dSJan Kara sizeof(struct qt_disk_dqdbheader) + 282884d179dSJan Kara i * info->dqi_entry_size; 283d26ac1a8SJan Kara kfree(buf); 284884d179dSJan Kara return blk; 285884d179dSJan Kara out_buf: 286d26ac1a8SJan Kara kfree(buf); 287884d179dSJan Kara return 0; 288884d179dSJan Kara } 289884d179dSJan Kara 290884d179dSJan Kara /* Insert reference to structure into the trie */ 291884d179dSJan Kara static int do_insert_tree(struct qtree_mem_dqinfo *info, struct dquot *dquot, 292884d179dSJan Kara uint *treeblk, int depth) 293884d179dSJan Kara { 294d26ac1a8SJan Kara char *buf = getdqbuf(info->dqi_usable_bs); 295884d179dSJan Kara int ret = 0, newson = 0, newact = 0; 296884d179dSJan Kara __le32 *ref; 297884d179dSJan Kara uint newblk; 298884d179dSJan Kara 299884d179dSJan Kara if (!buf) 300884d179dSJan Kara return -ENOMEM; 301884d179dSJan Kara if (!*treeblk) { 302884d179dSJan Kara ret = get_free_dqblk(info); 303884d179dSJan Kara if (ret < 0) 304884d179dSJan Kara goto out_buf; 305884d179dSJan Kara *treeblk = ret; 306884d179dSJan Kara memset(buf, 0, info->dqi_usable_bs); 307884d179dSJan Kara newact = 1; 308884d179dSJan Kara } else { 309884d179dSJan Kara ret = read_blk(info, *treeblk, buf); 310884d179dSJan Kara if (ret < 0) { 311fb5ffb0eSJiaying Zhang quota_error(dquot->dq_sb, "Can't read tree quota " 312fb5ffb0eSJiaying Zhang "block %u", *treeblk); 313884d179dSJan Kara goto out_buf; 314884d179dSJan Kara } 315884d179dSJan Kara } 316884d179dSJan Kara ref = (__le32 *)buf; 317884d179dSJan Kara newblk = le32_to_cpu(ref[get_index(info, dquot->dq_id, depth)]); 318884d179dSJan Kara if (!newblk) 319884d179dSJan Kara newson = 1; 320884d179dSJan Kara if (depth == info->dqi_qtree_depth - 1) { 321884d179dSJan Kara #ifdef __QUOTA_QT_PARANOIA 322884d179dSJan Kara if (newblk) { 323fb5ffb0eSJiaying Zhang quota_error(dquot->dq_sb, "Inserting already present " 324fb5ffb0eSJiaying Zhang "quota entry (block %u)", 325884d179dSJan Kara le32_to_cpu(ref[get_index(info, 326884d179dSJan Kara dquot->dq_id, depth)])); 327884d179dSJan Kara ret = -EIO; 328884d179dSJan Kara goto out_buf; 329884d179dSJan Kara } 330884d179dSJan Kara #endif 331884d179dSJan Kara newblk = find_free_dqentry(info, dquot, &ret); 332884d179dSJan Kara } else { 333884d179dSJan Kara ret = do_insert_tree(info, dquot, &newblk, depth+1); 334884d179dSJan Kara } 335884d179dSJan Kara if (newson && ret >= 0) { 336884d179dSJan Kara ref[get_index(info, dquot->dq_id, depth)] = 337884d179dSJan Kara cpu_to_le32(newblk); 338884d179dSJan Kara ret = write_blk(info, *treeblk, buf); 339884d179dSJan Kara } else if (newact && ret < 0) { 340884d179dSJan Kara put_free_dqblk(info, buf, *treeblk); 341884d179dSJan Kara } 342884d179dSJan Kara out_buf: 343d26ac1a8SJan Kara kfree(buf); 344884d179dSJan Kara return ret; 345884d179dSJan Kara } 346884d179dSJan Kara 347884d179dSJan Kara /* Wrapper for inserting quota structure into tree */ 348884d179dSJan Kara static inline int dq_insert_tree(struct qtree_mem_dqinfo *info, 349884d179dSJan Kara struct dquot *dquot) 350884d179dSJan Kara { 351884d179dSJan Kara int tmp = QT_TREEOFF; 352884d179dSJan Kara return do_insert_tree(info, dquot, &tmp, 0); 353884d179dSJan Kara } 354884d179dSJan Kara 355884d179dSJan Kara /* 356268157baSJan Kara * We don't have to be afraid of deadlocks as we never have quotas on quota 357268157baSJan Kara * files... 358884d179dSJan Kara */ 359884d179dSJan Kara int qtree_write_dquot(struct qtree_mem_dqinfo *info, struct dquot *dquot) 360884d179dSJan Kara { 361*4c376dcaSEric W. Biederman int type = dquot->dq_id.type; 362884d179dSJan Kara struct super_block *sb = dquot->dq_sb; 363884d179dSJan Kara ssize_t ret; 364d26ac1a8SJan Kara char *ddquot = getdqbuf(info->dqi_entry_size); 365884d179dSJan Kara 366884d179dSJan Kara if (!ddquot) 367884d179dSJan Kara return -ENOMEM; 368884d179dSJan Kara 369884d179dSJan Kara /* dq_off is guarded by dqio_mutex */ 370884d179dSJan Kara if (!dquot->dq_off) { 371884d179dSJan Kara ret = dq_insert_tree(info, dquot); 372884d179dSJan Kara if (ret < 0) { 373fb5ffb0eSJiaying Zhang quota_error(sb, "Error %zd occurred while creating " 374fb5ffb0eSJiaying Zhang "quota", ret); 375d26ac1a8SJan Kara kfree(ddquot); 376884d179dSJan Kara return ret; 377884d179dSJan Kara } 378884d179dSJan Kara } 379884d179dSJan Kara spin_lock(&dq_data_lock); 380884d179dSJan Kara info->dqi_ops->mem2disk_dqblk(ddquot, dquot); 381884d179dSJan Kara spin_unlock(&dq_data_lock); 382d26ac1a8SJan Kara ret = sb->s_op->quota_write(sb, type, ddquot, info->dqi_entry_size, 383d26ac1a8SJan Kara dquot->dq_off); 384884d179dSJan Kara if (ret != info->dqi_entry_size) { 385fb5ffb0eSJiaying Zhang quota_error(sb, "dquota write failed"); 386884d179dSJan Kara if (ret >= 0) 387884d179dSJan Kara ret = -ENOSPC; 388884d179dSJan Kara } else { 389884d179dSJan Kara ret = 0; 390884d179dSJan Kara } 391dde95888SDmitry Monakhov dqstats_inc(DQST_WRITES); 392d26ac1a8SJan Kara kfree(ddquot); 393884d179dSJan Kara 394884d179dSJan Kara return ret; 395884d179dSJan Kara } 396884d179dSJan Kara EXPORT_SYMBOL(qtree_write_dquot); 397884d179dSJan Kara 398884d179dSJan Kara /* Free dquot entry in data block */ 399884d179dSJan Kara static int free_dqentry(struct qtree_mem_dqinfo *info, struct dquot *dquot, 400884d179dSJan Kara uint blk) 401884d179dSJan Kara { 402884d179dSJan Kara struct qt_disk_dqdbheader *dh; 403d26ac1a8SJan Kara char *buf = getdqbuf(info->dqi_usable_bs); 404884d179dSJan Kara int ret = 0; 405884d179dSJan Kara 406884d179dSJan Kara if (!buf) 407884d179dSJan Kara return -ENOMEM; 408884d179dSJan Kara if (dquot->dq_off >> info->dqi_blocksize_bits != blk) { 409fb5ffb0eSJiaying Zhang quota_error(dquot->dq_sb, "Quota structure has offset to " 410fb5ffb0eSJiaying Zhang "other block (%u) than it should (%u)", blk, 411884d179dSJan Kara (uint)(dquot->dq_off >> info->dqi_blocksize_bits)); 412884d179dSJan Kara goto out_buf; 413884d179dSJan Kara } 414884d179dSJan Kara ret = read_blk(info, blk, buf); 415884d179dSJan Kara if (ret < 0) { 416fb5ffb0eSJiaying Zhang quota_error(dquot->dq_sb, "Can't read quota data block %u", 417fb5ffb0eSJiaying Zhang blk); 418884d179dSJan Kara goto out_buf; 419884d179dSJan Kara } 420884d179dSJan Kara dh = (struct qt_disk_dqdbheader *)buf; 421884d179dSJan Kara le16_add_cpu(&dh->dqdh_entries, -1); 422884d179dSJan Kara if (!le16_to_cpu(dh->dqdh_entries)) { /* Block got free? */ 423884d179dSJan Kara ret = remove_free_dqentry(info, buf, blk); 424884d179dSJan Kara if (ret >= 0) 425884d179dSJan Kara ret = put_free_dqblk(info, buf, blk); 426884d179dSJan Kara if (ret < 0) { 427fb5ffb0eSJiaying Zhang quota_error(dquot->dq_sb, "Can't move quota data block " 428fb5ffb0eSJiaying Zhang "(%u) to free list", blk); 429884d179dSJan Kara goto out_buf; 430884d179dSJan Kara } 431884d179dSJan Kara } else { 432884d179dSJan Kara memset(buf + 433884d179dSJan Kara (dquot->dq_off & ((1 << info->dqi_blocksize_bits) - 1)), 434884d179dSJan Kara 0, info->dqi_entry_size); 435884d179dSJan Kara if (le16_to_cpu(dh->dqdh_entries) == 436884d179dSJan Kara qtree_dqstr_in_blk(info) - 1) { 437884d179dSJan Kara /* Insert will write block itself */ 438884d179dSJan Kara ret = insert_free_dqentry(info, buf, blk); 439884d179dSJan Kara if (ret < 0) { 440fb5ffb0eSJiaying Zhang quota_error(dquot->dq_sb, "Can't insert quota " 441fb5ffb0eSJiaying Zhang "data block (%u) to free entry list", blk); 442884d179dSJan Kara goto out_buf; 443884d179dSJan Kara } 444884d179dSJan Kara } else { 445884d179dSJan Kara ret = write_blk(info, blk, buf); 446884d179dSJan Kara if (ret < 0) { 447fb5ffb0eSJiaying Zhang quota_error(dquot->dq_sb, "Can't write quota " 448fb5ffb0eSJiaying Zhang "data block %u", blk); 449884d179dSJan Kara goto out_buf; 450884d179dSJan Kara } 451884d179dSJan Kara } 452884d179dSJan Kara } 453884d179dSJan Kara dquot->dq_off = 0; /* Quota is now unattached */ 454884d179dSJan Kara out_buf: 455d26ac1a8SJan Kara kfree(buf); 456884d179dSJan Kara return ret; 457884d179dSJan Kara } 458884d179dSJan Kara 459884d179dSJan Kara /* Remove reference to dquot from tree */ 460884d179dSJan Kara static int remove_tree(struct qtree_mem_dqinfo *info, struct dquot *dquot, 461884d179dSJan Kara uint *blk, int depth) 462884d179dSJan Kara { 463d26ac1a8SJan Kara char *buf = getdqbuf(info->dqi_usable_bs); 464884d179dSJan Kara int ret = 0; 465884d179dSJan Kara uint newblk; 466884d179dSJan Kara __le32 *ref = (__le32 *)buf; 467884d179dSJan Kara 468884d179dSJan Kara if (!buf) 469884d179dSJan Kara return -ENOMEM; 470884d179dSJan Kara ret = read_blk(info, *blk, buf); 471884d179dSJan Kara if (ret < 0) { 472055adcbdSJoe Perches quota_error(dquot->dq_sb, "Can't read quota data block %u", 473055adcbdSJoe Perches *blk); 474884d179dSJan Kara goto out_buf; 475884d179dSJan Kara } 476884d179dSJan Kara newblk = le32_to_cpu(ref[get_index(info, dquot->dq_id, depth)]); 477884d179dSJan Kara if (depth == info->dqi_qtree_depth - 1) { 478884d179dSJan Kara ret = free_dqentry(info, dquot, newblk); 479884d179dSJan Kara newblk = 0; 480884d179dSJan Kara } else { 481884d179dSJan Kara ret = remove_tree(info, dquot, &newblk, depth+1); 482884d179dSJan Kara } 483884d179dSJan Kara if (ret >= 0 && !newblk) { 484884d179dSJan Kara int i; 485884d179dSJan Kara ref[get_index(info, dquot->dq_id, depth)] = cpu_to_le32(0); 486884d179dSJan Kara /* Block got empty? */ 487d26ac1a8SJan Kara for (i = 0; i < (info->dqi_usable_bs >> 2) && !ref[i]; i++) 488d26ac1a8SJan Kara ; 489884d179dSJan Kara /* Don't put the root block into the free block list */ 490884d179dSJan Kara if (i == (info->dqi_usable_bs >> 2) 491884d179dSJan Kara && *blk != QT_TREEOFF) { 492884d179dSJan Kara put_free_dqblk(info, buf, *blk); 493884d179dSJan Kara *blk = 0; 494884d179dSJan Kara } else { 495884d179dSJan Kara ret = write_blk(info, *blk, buf); 496884d179dSJan Kara if (ret < 0) 497055adcbdSJoe Perches quota_error(dquot->dq_sb, 498055adcbdSJoe Perches "Can't write quota tree block %u", 499055adcbdSJoe Perches *blk); 500884d179dSJan Kara } 501884d179dSJan Kara } 502884d179dSJan Kara out_buf: 503d26ac1a8SJan Kara kfree(buf); 504884d179dSJan Kara return ret; 505884d179dSJan Kara } 506884d179dSJan Kara 507884d179dSJan Kara /* Delete dquot from tree */ 508884d179dSJan Kara int qtree_delete_dquot(struct qtree_mem_dqinfo *info, struct dquot *dquot) 509884d179dSJan Kara { 510884d179dSJan Kara uint tmp = QT_TREEOFF; 511884d179dSJan Kara 512884d179dSJan Kara if (!dquot->dq_off) /* Even not allocated? */ 513884d179dSJan Kara return 0; 514884d179dSJan Kara return remove_tree(info, dquot, &tmp, 0); 515884d179dSJan Kara } 516884d179dSJan Kara EXPORT_SYMBOL(qtree_delete_dquot); 517884d179dSJan Kara 518884d179dSJan Kara /* Find entry in block */ 519884d179dSJan Kara static loff_t find_block_dqentry(struct qtree_mem_dqinfo *info, 520884d179dSJan Kara struct dquot *dquot, uint blk) 521884d179dSJan Kara { 522d26ac1a8SJan Kara char *buf = getdqbuf(info->dqi_usable_bs); 523884d179dSJan Kara loff_t ret = 0; 524884d179dSJan Kara int i; 525884d179dSJan Kara char *ddquot; 526884d179dSJan Kara 527884d179dSJan Kara if (!buf) 528884d179dSJan Kara return -ENOMEM; 529884d179dSJan Kara ret = read_blk(info, blk, buf); 530884d179dSJan Kara if (ret < 0) { 531fb5ffb0eSJiaying Zhang quota_error(dquot->dq_sb, "Can't read quota tree " 532fb5ffb0eSJiaying Zhang "block %u", blk); 533884d179dSJan Kara goto out_buf; 534884d179dSJan Kara } 535268157baSJan Kara ddquot = buf + sizeof(struct qt_disk_dqdbheader); 536268157baSJan Kara for (i = 0; i < qtree_dqstr_in_blk(info); i++) { 537268157baSJan Kara if (info->dqi_ops->is_id(ddquot, dquot)) 538268157baSJan Kara break; 539268157baSJan Kara ddquot += info->dqi_entry_size; 540268157baSJan Kara } 541884d179dSJan Kara if (i == qtree_dqstr_in_blk(info)) { 542*4c376dcaSEric W. Biederman quota_error(dquot->dq_sb, 543*4c376dcaSEric W. Biederman "Quota for id %u referenced but not present", 544*4c376dcaSEric W. Biederman from_kqid(&init_user_ns, dquot->dq_id)); 545884d179dSJan Kara ret = -EIO; 546884d179dSJan Kara goto out_buf; 547884d179dSJan Kara } else { 548884d179dSJan Kara ret = (blk << info->dqi_blocksize_bits) + sizeof(struct 549884d179dSJan Kara qt_disk_dqdbheader) + i * info->dqi_entry_size; 550884d179dSJan Kara } 551884d179dSJan Kara out_buf: 552d26ac1a8SJan Kara kfree(buf); 553884d179dSJan Kara return ret; 554884d179dSJan Kara } 555884d179dSJan Kara 556884d179dSJan Kara /* Find entry for given id in the tree */ 557884d179dSJan Kara static loff_t find_tree_dqentry(struct qtree_mem_dqinfo *info, 558884d179dSJan Kara struct dquot *dquot, uint blk, int depth) 559884d179dSJan Kara { 560d26ac1a8SJan Kara char *buf = getdqbuf(info->dqi_usable_bs); 561884d179dSJan Kara loff_t ret = 0; 562884d179dSJan Kara __le32 *ref = (__le32 *)buf; 563884d179dSJan Kara 564884d179dSJan Kara if (!buf) 565884d179dSJan Kara return -ENOMEM; 566884d179dSJan Kara ret = read_blk(info, blk, buf); 567884d179dSJan Kara if (ret < 0) { 568fb5ffb0eSJiaying Zhang quota_error(dquot->dq_sb, "Can't read quota tree block %u", 569fb5ffb0eSJiaying Zhang blk); 570884d179dSJan Kara goto out_buf; 571884d179dSJan Kara } 572884d179dSJan Kara ret = 0; 573884d179dSJan Kara blk = le32_to_cpu(ref[get_index(info, dquot->dq_id, depth)]); 574884d179dSJan Kara if (!blk) /* No reference? */ 575884d179dSJan Kara goto out_buf; 576884d179dSJan Kara if (depth < info->dqi_qtree_depth - 1) 577884d179dSJan Kara ret = find_tree_dqentry(info, dquot, blk, depth+1); 578884d179dSJan Kara else 579884d179dSJan Kara ret = find_block_dqentry(info, dquot, blk); 580884d179dSJan Kara out_buf: 581d26ac1a8SJan Kara kfree(buf); 582884d179dSJan Kara return ret; 583884d179dSJan Kara } 584884d179dSJan Kara 585884d179dSJan Kara /* Find entry for given id in the tree - wrapper function */ 586884d179dSJan Kara static inline loff_t find_dqentry(struct qtree_mem_dqinfo *info, 587884d179dSJan Kara struct dquot *dquot) 588884d179dSJan Kara { 589884d179dSJan Kara return find_tree_dqentry(info, dquot, QT_TREEOFF, 0); 590884d179dSJan Kara } 591884d179dSJan Kara 592884d179dSJan Kara int qtree_read_dquot(struct qtree_mem_dqinfo *info, struct dquot *dquot) 593884d179dSJan Kara { 594*4c376dcaSEric W. Biederman int type = dquot->dq_id.type; 595884d179dSJan Kara struct super_block *sb = dquot->dq_sb; 596884d179dSJan Kara loff_t offset; 597d26ac1a8SJan Kara char *ddquot; 598884d179dSJan Kara int ret = 0; 599884d179dSJan Kara 600884d179dSJan Kara #ifdef __QUOTA_QT_PARANOIA 601884d179dSJan Kara /* Invalidated quota? */ 602884d179dSJan Kara if (!sb_dqopt(dquot->dq_sb)->files[type]) { 603fb5ffb0eSJiaying Zhang quota_error(sb, "Quota invalidated while reading!"); 604884d179dSJan Kara return -EIO; 605884d179dSJan Kara } 606884d179dSJan Kara #endif 607884d179dSJan Kara /* Do we know offset of the dquot entry in the quota file? */ 608884d179dSJan Kara if (!dquot->dq_off) { 609884d179dSJan Kara offset = find_dqentry(info, dquot); 610884d179dSJan Kara if (offset <= 0) { /* Entry not present? */ 611884d179dSJan Kara if (offset < 0) 612fb5ffb0eSJiaying Zhang quota_error(sb,"Can't read quota structure " 613*4c376dcaSEric W. Biederman "for id %u", 614*4c376dcaSEric W. Biederman from_kqid(&init_user_ns, 615*4c376dcaSEric W. Biederman dquot->dq_id)); 616884d179dSJan Kara dquot->dq_off = 0; 617884d179dSJan Kara set_bit(DQ_FAKE_B, &dquot->dq_flags); 618884d179dSJan Kara memset(&dquot->dq_dqb, 0, sizeof(struct mem_dqblk)); 619884d179dSJan Kara ret = offset; 620884d179dSJan Kara goto out; 621884d179dSJan Kara } 622884d179dSJan Kara dquot->dq_off = offset; 623884d179dSJan Kara } 624884d179dSJan Kara ddquot = getdqbuf(info->dqi_entry_size); 625884d179dSJan Kara if (!ddquot) 626884d179dSJan Kara return -ENOMEM; 627d26ac1a8SJan Kara ret = sb->s_op->quota_read(sb, type, ddquot, info->dqi_entry_size, 628d26ac1a8SJan Kara dquot->dq_off); 629884d179dSJan Kara if (ret != info->dqi_entry_size) { 630884d179dSJan Kara if (ret >= 0) 631884d179dSJan Kara ret = -EIO; 632fb5ffb0eSJiaying Zhang quota_error(sb, "Error while reading quota structure for id %u", 633*4c376dcaSEric W. Biederman from_kqid(&init_user_ns, dquot->dq_id)); 634884d179dSJan Kara set_bit(DQ_FAKE_B, &dquot->dq_flags); 635884d179dSJan Kara memset(&dquot->dq_dqb, 0, sizeof(struct mem_dqblk)); 636d26ac1a8SJan Kara kfree(ddquot); 637884d179dSJan Kara goto out; 638884d179dSJan Kara } 639884d179dSJan Kara spin_lock(&dq_data_lock); 640884d179dSJan Kara info->dqi_ops->disk2mem_dqblk(dquot, ddquot); 641884d179dSJan Kara if (!dquot->dq_dqb.dqb_bhardlimit && 642884d179dSJan Kara !dquot->dq_dqb.dqb_bsoftlimit && 643884d179dSJan Kara !dquot->dq_dqb.dqb_ihardlimit && 644884d179dSJan Kara !dquot->dq_dqb.dqb_isoftlimit) 645884d179dSJan Kara set_bit(DQ_FAKE_B, &dquot->dq_flags); 646884d179dSJan Kara spin_unlock(&dq_data_lock); 647d26ac1a8SJan Kara kfree(ddquot); 648884d179dSJan Kara out: 649dde95888SDmitry Monakhov dqstats_inc(DQST_READS); 650884d179dSJan Kara return ret; 651884d179dSJan Kara } 652884d179dSJan Kara EXPORT_SYMBOL(qtree_read_dquot); 653884d179dSJan Kara 654884d179dSJan Kara /* Check whether dquot should not be deleted. We know we are 655884d179dSJan Kara * the only one operating on dquot (thanks to dq_lock) */ 656884d179dSJan Kara int qtree_release_dquot(struct qtree_mem_dqinfo *info, struct dquot *dquot) 657884d179dSJan Kara { 658268157baSJan Kara if (test_bit(DQ_FAKE_B, &dquot->dq_flags) && 659268157baSJan Kara !(dquot->dq_dqb.dqb_curinodes | dquot->dq_dqb.dqb_curspace)) 660884d179dSJan Kara return qtree_delete_dquot(info, dquot); 661884d179dSJan Kara return 0; 662884d179dSJan Kara } 663884d179dSJan Kara EXPORT_SYMBOL(qtree_release_dquot); 664