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*0066373dSJan Kara static int __get_index(struct qtree_mem_dqinfo *info, qid_t id, int depth) 26884d179dSJan Kara { 27884d179dSJan Kara unsigned int epb = info->dqi_usable_bs >> 2; 28884d179dSJan Kara 29884d179dSJan Kara depth = info->dqi_qtree_depth - depth - 1; 30884d179dSJan Kara while (depth--) 31884d179dSJan Kara id /= epb; 32884d179dSJan Kara return id % epb; 33884d179dSJan Kara } 34884d179dSJan Kara 35*0066373dSJan Kara static int get_index(struct qtree_mem_dqinfo *info, struct kqid qid, int depth) 36*0066373dSJan Kara { 37*0066373dSJan Kara qid_t id = from_kqid(&init_user_ns, qid); 38*0066373dSJan Kara 39*0066373dSJan Kara return __get_index(info, id, depth); 40*0066373dSJan Kara } 41*0066373dSJan Kara 42884d179dSJan Kara /* Number of entries in one blocks */ 437a2435d8SJan Kara static int qtree_dqstr_in_blk(struct qtree_mem_dqinfo *info) 44884d179dSJan Kara { 45884d179dSJan Kara return (info->dqi_usable_bs - sizeof(struct qt_disk_dqdbheader)) 46884d179dSJan Kara / info->dqi_entry_size; 47884d179dSJan Kara } 48884d179dSJan Kara 49d26ac1a8SJan Kara static char *getdqbuf(size_t size) 50884d179dSJan Kara { 51d26ac1a8SJan Kara char *buf = kmalloc(size, GFP_NOFS); 52884d179dSJan Kara if (!buf) 53268157baSJan Kara printk(KERN_WARNING 54268157baSJan Kara "VFS: Not enough memory for quota buffers.\n"); 55884d179dSJan Kara return buf; 56884d179dSJan Kara } 57884d179dSJan Kara 587a2435d8SJan Kara static ssize_t read_blk(struct qtree_mem_dqinfo *info, uint blk, char *buf) 59884d179dSJan Kara { 60884d179dSJan Kara struct super_block *sb = info->dqi_sb; 61884d179dSJan Kara 62884d179dSJan Kara memset(buf, 0, info->dqi_usable_bs); 63d26ac1a8SJan Kara return sb->s_op->quota_read(sb, info->dqi_type, buf, 64884d179dSJan Kara info->dqi_usable_bs, blk << info->dqi_blocksize_bits); 65884d179dSJan Kara } 66884d179dSJan Kara 677a2435d8SJan Kara static ssize_t write_blk(struct qtree_mem_dqinfo *info, uint blk, char *buf) 68884d179dSJan Kara { 69884d179dSJan Kara struct super_block *sb = info->dqi_sb; 701907131bSJiaying Zhang ssize_t ret; 71884d179dSJan Kara 721907131bSJiaying Zhang ret = sb->s_op->quota_write(sb, info->dqi_type, buf, 73884d179dSJan Kara info->dqi_usable_bs, blk << info->dqi_blocksize_bits); 741907131bSJiaying Zhang if (ret != info->dqi_usable_bs) { 75fb5ffb0eSJiaying Zhang quota_error(sb, "dquota write failed"); 761907131bSJiaying Zhang if (ret >= 0) 771907131bSJiaying Zhang ret = -EIO; 781907131bSJiaying Zhang } 791907131bSJiaying Zhang return ret; 80884d179dSJan Kara } 81884d179dSJan Kara 82884d179dSJan Kara /* Remove empty block from list and return it */ 83884d179dSJan Kara static int get_free_dqblk(struct qtree_mem_dqinfo *info) 84884d179dSJan Kara { 85d26ac1a8SJan Kara char *buf = getdqbuf(info->dqi_usable_bs); 86884d179dSJan Kara struct qt_disk_dqdbheader *dh = (struct qt_disk_dqdbheader *)buf; 87884d179dSJan Kara int ret, blk; 88884d179dSJan Kara 89884d179dSJan Kara if (!buf) 90884d179dSJan Kara return -ENOMEM; 91884d179dSJan Kara if (info->dqi_free_blk) { 92884d179dSJan Kara blk = info->dqi_free_blk; 93884d179dSJan Kara ret = read_blk(info, blk, buf); 94884d179dSJan Kara if (ret < 0) 95884d179dSJan Kara goto out_buf; 96884d179dSJan Kara info->dqi_free_blk = le32_to_cpu(dh->dqdh_next_free); 97884d179dSJan Kara } 98884d179dSJan Kara else { 99884d179dSJan Kara memset(buf, 0, info->dqi_usable_bs); 100884d179dSJan Kara /* Assure block allocation... */ 101884d179dSJan Kara ret = write_blk(info, info->dqi_blocks, buf); 102884d179dSJan Kara if (ret < 0) 103884d179dSJan Kara goto out_buf; 104884d179dSJan Kara blk = info->dqi_blocks++; 105884d179dSJan Kara } 106884d179dSJan Kara mark_info_dirty(info->dqi_sb, info->dqi_type); 107884d179dSJan Kara ret = blk; 108884d179dSJan Kara out_buf: 109d26ac1a8SJan Kara kfree(buf); 110884d179dSJan Kara return ret; 111884d179dSJan Kara } 112884d179dSJan Kara 113884d179dSJan Kara /* Insert empty block to the list */ 114d26ac1a8SJan Kara static int put_free_dqblk(struct qtree_mem_dqinfo *info, char *buf, uint blk) 115884d179dSJan Kara { 116884d179dSJan Kara struct qt_disk_dqdbheader *dh = (struct qt_disk_dqdbheader *)buf; 117884d179dSJan Kara int err; 118884d179dSJan Kara 119884d179dSJan Kara dh->dqdh_next_free = cpu_to_le32(info->dqi_free_blk); 120884d179dSJan Kara dh->dqdh_prev_free = cpu_to_le32(0); 121884d179dSJan Kara dh->dqdh_entries = cpu_to_le16(0); 122884d179dSJan Kara err = write_blk(info, blk, buf); 123884d179dSJan Kara if (err < 0) 124884d179dSJan Kara return err; 125884d179dSJan Kara info->dqi_free_blk = blk; 126884d179dSJan Kara mark_info_dirty(info->dqi_sb, info->dqi_type); 127884d179dSJan Kara return 0; 128884d179dSJan Kara } 129884d179dSJan Kara 130884d179dSJan Kara /* Remove given block from the list of blocks with free entries */ 131268157baSJan Kara static int remove_free_dqentry(struct qtree_mem_dqinfo *info, char *buf, 132268157baSJan Kara uint blk) 133884d179dSJan Kara { 134d26ac1a8SJan Kara char *tmpbuf = getdqbuf(info->dqi_usable_bs); 135884d179dSJan Kara struct qt_disk_dqdbheader *dh = (struct qt_disk_dqdbheader *)buf; 136884d179dSJan Kara uint nextblk = le32_to_cpu(dh->dqdh_next_free); 137884d179dSJan Kara uint prevblk = le32_to_cpu(dh->dqdh_prev_free); 138884d179dSJan Kara int err; 139884d179dSJan Kara 140884d179dSJan Kara if (!tmpbuf) 141884d179dSJan Kara return -ENOMEM; 142884d179dSJan Kara if (nextblk) { 143884d179dSJan Kara err = read_blk(info, nextblk, tmpbuf); 144884d179dSJan Kara if (err < 0) 145884d179dSJan Kara goto out_buf; 146884d179dSJan Kara ((struct qt_disk_dqdbheader *)tmpbuf)->dqdh_prev_free = 147884d179dSJan Kara dh->dqdh_prev_free; 148884d179dSJan Kara err = write_blk(info, nextblk, tmpbuf); 149884d179dSJan Kara if (err < 0) 150884d179dSJan Kara goto out_buf; 151884d179dSJan Kara } 152884d179dSJan Kara if (prevblk) { 153884d179dSJan Kara err = read_blk(info, prevblk, tmpbuf); 154884d179dSJan Kara if (err < 0) 155884d179dSJan Kara goto out_buf; 156884d179dSJan Kara ((struct qt_disk_dqdbheader *)tmpbuf)->dqdh_next_free = 157884d179dSJan Kara dh->dqdh_next_free; 158884d179dSJan Kara err = write_blk(info, prevblk, tmpbuf); 159884d179dSJan Kara if (err < 0) 160884d179dSJan Kara goto out_buf; 161884d179dSJan Kara } else { 162884d179dSJan Kara info->dqi_free_entry = nextblk; 163884d179dSJan Kara mark_info_dirty(info->dqi_sb, info->dqi_type); 164884d179dSJan Kara } 165d26ac1a8SJan Kara kfree(tmpbuf); 166884d179dSJan Kara dh->dqdh_next_free = dh->dqdh_prev_free = cpu_to_le32(0); 167884d179dSJan Kara /* No matter whether write succeeds block is out of list */ 168884d179dSJan Kara if (write_blk(info, blk, buf) < 0) 169fb5ffb0eSJiaying Zhang quota_error(info->dqi_sb, "Can't write block (%u) " 170fb5ffb0eSJiaying Zhang "with free entries", blk); 171884d179dSJan Kara return 0; 172884d179dSJan Kara out_buf: 173d26ac1a8SJan Kara kfree(tmpbuf); 174884d179dSJan Kara return err; 175884d179dSJan Kara } 176884d179dSJan Kara 177884d179dSJan Kara /* Insert given block to the beginning of list with free entries */ 178268157baSJan Kara static int insert_free_dqentry(struct qtree_mem_dqinfo *info, char *buf, 179268157baSJan Kara uint blk) 180884d179dSJan Kara { 181d26ac1a8SJan Kara char *tmpbuf = getdqbuf(info->dqi_usable_bs); 182884d179dSJan Kara struct qt_disk_dqdbheader *dh = (struct qt_disk_dqdbheader *)buf; 183884d179dSJan Kara int err; 184884d179dSJan Kara 185884d179dSJan Kara if (!tmpbuf) 186884d179dSJan Kara return -ENOMEM; 187884d179dSJan Kara dh->dqdh_next_free = cpu_to_le32(info->dqi_free_entry); 188884d179dSJan Kara dh->dqdh_prev_free = cpu_to_le32(0); 189884d179dSJan Kara err = write_blk(info, blk, buf); 190884d179dSJan Kara if (err < 0) 191884d179dSJan Kara goto out_buf; 192884d179dSJan Kara if (info->dqi_free_entry) { 193884d179dSJan Kara err = read_blk(info, info->dqi_free_entry, tmpbuf); 194884d179dSJan Kara if (err < 0) 195884d179dSJan Kara goto out_buf; 196884d179dSJan Kara ((struct qt_disk_dqdbheader *)tmpbuf)->dqdh_prev_free = 197884d179dSJan Kara cpu_to_le32(blk); 198884d179dSJan Kara err = write_blk(info, info->dqi_free_entry, tmpbuf); 199884d179dSJan Kara if (err < 0) 200884d179dSJan Kara goto out_buf; 201884d179dSJan Kara } 202d26ac1a8SJan Kara kfree(tmpbuf); 203884d179dSJan Kara info->dqi_free_entry = blk; 204884d179dSJan Kara mark_info_dirty(info->dqi_sb, info->dqi_type); 205884d179dSJan Kara return 0; 206884d179dSJan Kara out_buf: 207d26ac1a8SJan Kara kfree(tmpbuf); 208884d179dSJan Kara return err; 209884d179dSJan Kara } 210884d179dSJan Kara 211884d179dSJan Kara /* Is the entry in the block free? */ 212884d179dSJan Kara int qtree_entry_unused(struct qtree_mem_dqinfo *info, char *disk) 213884d179dSJan Kara { 214884d179dSJan Kara int i; 215884d179dSJan Kara 216884d179dSJan Kara for (i = 0; i < info->dqi_entry_size; i++) 217884d179dSJan Kara if (disk[i]) 218884d179dSJan Kara return 0; 219884d179dSJan Kara return 1; 220884d179dSJan Kara } 221884d179dSJan Kara EXPORT_SYMBOL(qtree_entry_unused); 222884d179dSJan Kara 223884d179dSJan Kara /* Find space for dquot */ 224884d179dSJan Kara static uint find_free_dqentry(struct qtree_mem_dqinfo *info, 225884d179dSJan Kara struct dquot *dquot, int *err) 226884d179dSJan Kara { 227884d179dSJan Kara uint blk, i; 228884d179dSJan Kara struct qt_disk_dqdbheader *dh; 229d26ac1a8SJan Kara char *buf = getdqbuf(info->dqi_usable_bs); 230884d179dSJan Kara char *ddquot; 231884d179dSJan Kara 232884d179dSJan Kara *err = 0; 233884d179dSJan Kara if (!buf) { 234884d179dSJan Kara *err = -ENOMEM; 235884d179dSJan Kara return 0; 236884d179dSJan Kara } 237884d179dSJan Kara dh = (struct qt_disk_dqdbheader *)buf; 238884d179dSJan Kara if (info->dqi_free_entry) { 239884d179dSJan Kara blk = info->dqi_free_entry; 240884d179dSJan Kara *err = read_blk(info, blk, buf); 241884d179dSJan Kara if (*err < 0) 242884d179dSJan Kara goto out_buf; 243884d179dSJan Kara } else { 244884d179dSJan Kara blk = get_free_dqblk(info); 245884d179dSJan Kara if ((int)blk < 0) { 246884d179dSJan Kara *err = blk; 247d26ac1a8SJan Kara kfree(buf); 248884d179dSJan Kara return 0; 249884d179dSJan Kara } 250884d179dSJan Kara memset(buf, 0, info->dqi_usable_bs); 251268157baSJan Kara /* This is enough as the block is already zeroed and the entry 252268157baSJan Kara * list is empty... */ 253884d179dSJan Kara info->dqi_free_entry = blk; 2544c376dcaSEric W. Biederman mark_info_dirty(dquot->dq_sb, dquot->dq_id.type); 255884d179dSJan Kara } 256884d179dSJan Kara /* Block will be full? */ 257884d179dSJan Kara if (le16_to_cpu(dh->dqdh_entries) + 1 >= qtree_dqstr_in_blk(info)) { 258884d179dSJan Kara *err = remove_free_dqentry(info, buf, blk); 259884d179dSJan Kara if (*err < 0) { 260fb5ffb0eSJiaying Zhang quota_error(dquot->dq_sb, "Can't remove block (%u) " 261fb5ffb0eSJiaying Zhang "from entry free list", blk); 262884d179dSJan Kara goto out_buf; 263884d179dSJan Kara } 264884d179dSJan Kara } 265884d179dSJan Kara le16_add_cpu(&dh->dqdh_entries, 1); 266884d179dSJan Kara /* Find free structure in block */ 267268157baSJan Kara ddquot = buf + sizeof(struct qt_disk_dqdbheader); 268268157baSJan Kara for (i = 0; i < qtree_dqstr_in_blk(info); i++) { 269268157baSJan Kara if (qtree_entry_unused(info, ddquot)) 270268157baSJan Kara break; 271268157baSJan Kara ddquot += info->dqi_entry_size; 272268157baSJan Kara } 273884d179dSJan Kara #ifdef __QUOTA_QT_PARANOIA 274884d179dSJan Kara if (i == qtree_dqstr_in_blk(info)) { 275fb5ffb0eSJiaying Zhang quota_error(dquot->dq_sb, "Data block full but it shouldn't"); 276884d179dSJan Kara *err = -EIO; 277884d179dSJan Kara goto out_buf; 278884d179dSJan Kara } 279884d179dSJan Kara #endif 280884d179dSJan Kara *err = write_blk(info, blk, buf); 281884d179dSJan Kara if (*err < 0) { 282fb5ffb0eSJiaying Zhang quota_error(dquot->dq_sb, "Can't write quota data block %u", 283fb5ffb0eSJiaying Zhang blk); 284884d179dSJan Kara goto out_buf; 285884d179dSJan Kara } 286884d179dSJan Kara dquot->dq_off = (blk << info->dqi_blocksize_bits) + 287884d179dSJan Kara sizeof(struct qt_disk_dqdbheader) + 288884d179dSJan Kara i * info->dqi_entry_size; 289d26ac1a8SJan Kara kfree(buf); 290884d179dSJan Kara return blk; 291884d179dSJan Kara out_buf: 292d26ac1a8SJan Kara kfree(buf); 293884d179dSJan Kara return 0; 294884d179dSJan Kara } 295884d179dSJan Kara 296884d179dSJan Kara /* Insert reference to structure into the trie */ 297884d179dSJan Kara static int do_insert_tree(struct qtree_mem_dqinfo *info, struct dquot *dquot, 298884d179dSJan Kara uint *treeblk, int depth) 299884d179dSJan Kara { 300d26ac1a8SJan Kara char *buf = getdqbuf(info->dqi_usable_bs); 301884d179dSJan Kara int ret = 0, newson = 0, newact = 0; 302884d179dSJan Kara __le32 *ref; 303884d179dSJan Kara uint newblk; 304884d179dSJan Kara 305884d179dSJan Kara if (!buf) 306884d179dSJan Kara return -ENOMEM; 307884d179dSJan Kara if (!*treeblk) { 308884d179dSJan Kara ret = get_free_dqblk(info); 309884d179dSJan Kara if (ret < 0) 310884d179dSJan Kara goto out_buf; 311884d179dSJan Kara *treeblk = ret; 312884d179dSJan Kara memset(buf, 0, info->dqi_usable_bs); 313884d179dSJan Kara newact = 1; 314884d179dSJan Kara } else { 315884d179dSJan Kara ret = read_blk(info, *treeblk, buf); 316884d179dSJan Kara if (ret < 0) { 317fb5ffb0eSJiaying Zhang quota_error(dquot->dq_sb, "Can't read tree quota " 318fb5ffb0eSJiaying Zhang "block %u", *treeblk); 319884d179dSJan Kara goto out_buf; 320884d179dSJan Kara } 321884d179dSJan Kara } 322884d179dSJan Kara ref = (__le32 *)buf; 323884d179dSJan Kara newblk = le32_to_cpu(ref[get_index(info, dquot->dq_id, depth)]); 324884d179dSJan Kara if (!newblk) 325884d179dSJan Kara newson = 1; 326884d179dSJan Kara if (depth == info->dqi_qtree_depth - 1) { 327884d179dSJan Kara #ifdef __QUOTA_QT_PARANOIA 328884d179dSJan Kara if (newblk) { 329fb5ffb0eSJiaying Zhang quota_error(dquot->dq_sb, "Inserting already present " 330fb5ffb0eSJiaying Zhang "quota entry (block %u)", 331884d179dSJan Kara le32_to_cpu(ref[get_index(info, 332884d179dSJan Kara dquot->dq_id, depth)])); 333884d179dSJan Kara ret = -EIO; 334884d179dSJan Kara goto out_buf; 335884d179dSJan Kara } 336884d179dSJan Kara #endif 337884d179dSJan Kara newblk = find_free_dqentry(info, dquot, &ret); 338884d179dSJan Kara } else { 339884d179dSJan Kara ret = do_insert_tree(info, dquot, &newblk, depth+1); 340884d179dSJan Kara } 341884d179dSJan Kara if (newson && ret >= 0) { 342884d179dSJan Kara ref[get_index(info, dquot->dq_id, depth)] = 343884d179dSJan Kara cpu_to_le32(newblk); 344884d179dSJan Kara ret = write_blk(info, *treeblk, buf); 345884d179dSJan Kara } else if (newact && ret < 0) { 346884d179dSJan Kara put_free_dqblk(info, buf, *treeblk); 347884d179dSJan Kara } 348884d179dSJan Kara out_buf: 349d26ac1a8SJan Kara kfree(buf); 350884d179dSJan Kara return ret; 351884d179dSJan Kara } 352884d179dSJan Kara 353884d179dSJan Kara /* Wrapper for inserting quota structure into tree */ 354884d179dSJan Kara static inline int dq_insert_tree(struct qtree_mem_dqinfo *info, 355884d179dSJan Kara struct dquot *dquot) 356884d179dSJan Kara { 357884d179dSJan Kara int tmp = QT_TREEOFF; 35869a25ee2SKonstantin Khlebnikov 35969a25ee2SKonstantin Khlebnikov #ifdef __QUOTA_QT_PARANOIA 36069a25ee2SKonstantin Khlebnikov if (info->dqi_blocks <= QT_TREEOFF) { 36169a25ee2SKonstantin Khlebnikov quota_error(dquot->dq_sb, "Quota tree root isn't allocated!"); 36269a25ee2SKonstantin Khlebnikov return -EIO; 36369a25ee2SKonstantin Khlebnikov } 36469a25ee2SKonstantin Khlebnikov #endif 365884d179dSJan Kara return do_insert_tree(info, dquot, &tmp, 0); 366884d179dSJan Kara } 367884d179dSJan Kara 368884d179dSJan Kara /* 369268157baSJan Kara * We don't have to be afraid of deadlocks as we never have quotas on quota 370268157baSJan Kara * files... 371884d179dSJan Kara */ 372884d179dSJan Kara int qtree_write_dquot(struct qtree_mem_dqinfo *info, struct dquot *dquot) 373884d179dSJan Kara { 3744c376dcaSEric W. Biederman int type = dquot->dq_id.type; 375884d179dSJan Kara struct super_block *sb = dquot->dq_sb; 376884d179dSJan Kara ssize_t ret; 377d26ac1a8SJan Kara char *ddquot = getdqbuf(info->dqi_entry_size); 378884d179dSJan Kara 379884d179dSJan Kara if (!ddquot) 380884d179dSJan Kara return -ENOMEM; 381884d179dSJan Kara 382884d179dSJan Kara /* dq_off is guarded by dqio_mutex */ 383884d179dSJan Kara if (!dquot->dq_off) { 384884d179dSJan Kara ret = dq_insert_tree(info, dquot); 385884d179dSJan Kara if (ret < 0) { 386fb5ffb0eSJiaying Zhang quota_error(sb, "Error %zd occurred while creating " 387fb5ffb0eSJiaying Zhang "quota", ret); 388d26ac1a8SJan Kara kfree(ddquot); 389884d179dSJan Kara return ret; 390884d179dSJan Kara } 391884d179dSJan Kara } 392884d179dSJan Kara spin_lock(&dq_data_lock); 393884d179dSJan Kara info->dqi_ops->mem2disk_dqblk(ddquot, dquot); 394884d179dSJan Kara spin_unlock(&dq_data_lock); 395d26ac1a8SJan Kara ret = sb->s_op->quota_write(sb, type, ddquot, info->dqi_entry_size, 396d26ac1a8SJan Kara dquot->dq_off); 397884d179dSJan Kara if (ret != info->dqi_entry_size) { 398fb5ffb0eSJiaying Zhang quota_error(sb, "dquota write failed"); 399884d179dSJan Kara if (ret >= 0) 400884d179dSJan Kara ret = -ENOSPC; 401884d179dSJan Kara } else { 402884d179dSJan Kara ret = 0; 403884d179dSJan Kara } 404dde95888SDmitry Monakhov dqstats_inc(DQST_WRITES); 405d26ac1a8SJan Kara kfree(ddquot); 406884d179dSJan Kara 407884d179dSJan Kara return ret; 408884d179dSJan Kara } 409884d179dSJan Kara EXPORT_SYMBOL(qtree_write_dquot); 410884d179dSJan Kara 411884d179dSJan Kara /* Free dquot entry in data block */ 412884d179dSJan Kara static int free_dqentry(struct qtree_mem_dqinfo *info, struct dquot *dquot, 413884d179dSJan Kara uint blk) 414884d179dSJan Kara { 415884d179dSJan Kara struct qt_disk_dqdbheader *dh; 416d26ac1a8SJan Kara char *buf = getdqbuf(info->dqi_usable_bs); 417884d179dSJan Kara int ret = 0; 418884d179dSJan Kara 419884d179dSJan Kara if (!buf) 420884d179dSJan Kara return -ENOMEM; 421884d179dSJan Kara if (dquot->dq_off >> info->dqi_blocksize_bits != blk) { 422fb5ffb0eSJiaying Zhang quota_error(dquot->dq_sb, "Quota structure has offset to " 423fb5ffb0eSJiaying Zhang "other block (%u) than it should (%u)", blk, 424884d179dSJan Kara (uint)(dquot->dq_off >> info->dqi_blocksize_bits)); 425884d179dSJan Kara goto out_buf; 426884d179dSJan Kara } 427884d179dSJan Kara ret = read_blk(info, blk, buf); 428884d179dSJan Kara if (ret < 0) { 429fb5ffb0eSJiaying Zhang quota_error(dquot->dq_sb, "Can't read quota data block %u", 430fb5ffb0eSJiaying Zhang blk); 431884d179dSJan Kara goto out_buf; 432884d179dSJan Kara } 433884d179dSJan Kara dh = (struct qt_disk_dqdbheader *)buf; 434884d179dSJan Kara le16_add_cpu(&dh->dqdh_entries, -1); 435884d179dSJan Kara if (!le16_to_cpu(dh->dqdh_entries)) { /* Block got free? */ 436884d179dSJan Kara ret = remove_free_dqentry(info, buf, blk); 437884d179dSJan Kara if (ret >= 0) 438884d179dSJan Kara ret = put_free_dqblk(info, buf, blk); 439884d179dSJan Kara if (ret < 0) { 440fb5ffb0eSJiaying Zhang quota_error(dquot->dq_sb, "Can't move quota data block " 441fb5ffb0eSJiaying Zhang "(%u) to free list", blk); 442884d179dSJan Kara goto out_buf; 443884d179dSJan Kara } 444884d179dSJan Kara } else { 445884d179dSJan Kara memset(buf + 446884d179dSJan Kara (dquot->dq_off & ((1 << info->dqi_blocksize_bits) - 1)), 447884d179dSJan Kara 0, info->dqi_entry_size); 448884d179dSJan Kara if (le16_to_cpu(dh->dqdh_entries) == 449884d179dSJan Kara qtree_dqstr_in_blk(info) - 1) { 450884d179dSJan Kara /* Insert will write block itself */ 451884d179dSJan Kara ret = insert_free_dqentry(info, buf, blk); 452884d179dSJan Kara if (ret < 0) { 453fb5ffb0eSJiaying Zhang quota_error(dquot->dq_sb, "Can't insert quota " 454fb5ffb0eSJiaying Zhang "data block (%u) to free entry list", blk); 455884d179dSJan Kara goto out_buf; 456884d179dSJan Kara } 457884d179dSJan Kara } else { 458884d179dSJan Kara ret = write_blk(info, blk, buf); 459884d179dSJan Kara if (ret < 0) { 460fb5ffb0eSJiaying Zhang quota_error(dquot->dq_sb, "Can't write quota " 461fb5ffb0eSJiaying Zhang "data block %u", blk); 462884d179dSJan Kara goto out_buf; 463884d179dSJan Kara } 464884d179dSJan Kara } 465884d179dSJan Kara } 466884d179dSJan Kara dquot->dq_off = 0; /* Quota is now unattached */ 467884d179dSJan Kara out_buf: 468d26ac1a8SJan Kara kfree(buf); 469884d179dSJan Kara return ret; 470884d179dSJan Kara } 471884d179dSJan Kara 472884d179dSJan Kara /* Remove reference to dquot from tree */ 473884d179dSJan Kara static int remove_tree(struct qtree_mem_dqinfo *info, struct dquot *dquot, 474884d179dSJan Kara uint *blk, int depth) 475884d179dSJan Kara { 476d26ac1a8SJan Kara char *buf = getdqbuf(info->dqi_usable_bs); 477884d179dSJan Kara int ret = 0; 478884d179dSJan Kara uint newblk; 479884d179dSJan Kara __le32 *ref = (__le32 *)buf; 480884d179dSJan Kara 481884d179dSJan Kara if (!buf) 482884d179dSJan Kara return -ENOMEM; 483884d179dSJan Kara ret = read_blk(info, *blk, buf); 484884d179dSJan Kara if (ret < 0) { 485055adcbdSJoe Perches quota_error(dquot->dq_sb, "Can't read quota data block %u", 486055adcbdSJoe Perches *blk); 487884d179dSJan Kara goto out_buf; 488884d179dSJan Kara } 489884d179dSJan Kara newblk = le32_to_cpu(ref[get_index(info, dquot->dq_id, depth)]); 490884d179dSJan Kara if (depth == info->dqi_qtree_depth - 1) { 491884d179dSJan Kara ret = free_dqentry(info, dquot, newblk); 492884d179dSJan Kara newblk = 0; 493884d179dSJan Kara } else { 494884d179dSJan Kara ret = remove_tree(info, dquot, &newblk, depth+1); 495884d179dSJan Kara } 496884d179dSJan Kara if (ret >= 0 && !newblk) { 497884d179dSJan Kara int i; 498884d179dSJan Kara ref[get_index(info, dquot->dq_id, depth)] = cpu_to_le32(0); 499884d179dSJan Kara /* Block got empty? */ 500d26ac1a8SJan Kara for (i = 0; i < (info->dqi_usable_bs >> 2) && !ref[i]; i++) 501d26ac1a8SJan Kara ; 502884d179dSJan Kara /* Don't put the root block into the free block list */ 503884d179dSJan Kara if (i == (info->dqi_usable_bs >> 2) 504884d179dSJan Kara && *blk != QT_TREEOFF) { 505884d179dSJan Kara put_free_dqblk(info, buf, *blk); 506884d179dSJan Kara *blk = 0; 507884d179dSJan Kara } else { 508884d179dSJan Kara ret = write_blk(info, *blk, buf); 509884d179dSJan Kara if (ret < 0) 510055adcbdSJoe Perches quota_error(dquot->dq_sb, 511055adcbdSJoe Perches "Can't write quota tree block %u", 512055adcbdSJoe Perches *blk); 513884d179dSJan Kara } 514884d179dSJan Kara } 515884d179dSJan Kara out_buf: 516d26ac1a8SJan Kara kfree(buf); 517884d179dSJan Kara return ret; 518884d179dSJan Kara } 519884d179dSJan Kara 520884d179dSJan Kara /* Delete dquot from tree */ 521884d179dSJan Kara int qtree_delete_dquot(struct qtree_mem_dqinfo *info, struct dquot *dquot) 522884d179dSJan Kara { 523884d179dSJan Kara uint tmp = QT_TREEOFF; 524884d179dSJan Kara 525884d179dSJan Kara if (!dquot->dq_off) /* Even not allocated? */ 526884d179dSJan Kara return 0; 527884d179dSJan Kara return remove_tree(info, dquot, &tmp, 0); 528884d179dSJan Kara } 529884d179dSJan Kara EXPORT_SYMBOL(qtree_delete_dquot); 530884d179dSJan Kara 531884d179dSJan Kara /* Find entry in block */ 532884d179dSJan Kara static loff_t find_block_dqentry(struct qtree_mem_dqinfo *info, 533884d179dSJan Kara struct dquot *dquot, uint blk) 534884d179dSJan Kara { 535d26ac1a8SJan Kara char *buf = getdqbuf(info->dqi_usable_bs); 536884d179dSJan Kara loff_t ret = 0; 537884d179dSJan Kara int i; 538884d179dSJan Kara char *ddquot; 539884d179dSJan Kara 540884d179dSJan Kara if (!buf) 541884d179dSJan Kara return -ENOMEM; 542884d179dSJan Kara ret = read_blk(info, blk, buf); 543884d179dSJan Kara if (ret < 0) { 544fb5ffb0eSJiaying Zhang quota_error(dquot->dq_sb, "Can't read quota tree " 545fb5ffb0eSJiaying Zhang "block %u", blk); 546884d179dSJan Kara goto out_buf; 547884d179dSJan Kara } 548268157baSJan Kara ddquot = buf + sizeof(struct qt_disk_dqdbheader); 549268157baSJan Kara for (i = 0; i < qtree_dqstr_in_blk(info); i++) { 550268157baSJan Kara if (info->dqi_ops->is_id(ddquot, dquot)) 551268157baSJan Kara break; 552268157baSJan Kara ddquot += info->dqi_entry_size; 553268157baSJan Kara } 554884d179dSJan Kara if (i == qtree_dqstr_in_blk(info)) { 5554c376dcaSEric W. Biederman quota_error(dquot->dq_sb, 5564c376dcaSEric W. Biederman "Quota for id %u referenced but not present", 5574c376dcaSEric W. Biederman from_kqid(&init_user_ns, dquot->dq_id)); 558884d179dSJan Kara ret = -EIO; 559884d179dSJan Kara goto out_buf; 560884d179dSJan Kara } else { 561884d179dSJan Kara ret = (blk << info->dqi_blocksize_bits) + sizeof(struct 562884d179dSJan Kara qt_disk_dqdbheader) + i * info->dqi_entry_size; 563884d179dSJan Kara } 564884d179dSJan Kara out_buf: 565d26ac1a8SJan Kara kfree(buf); 566884d179dSJan Kara return ret; 567884d179dSJan Kara } 568884d179dSJan Kara 569884d179dSJan Kara /* Find entry for given id in the tree */ 570884d179dSJan Kara static loff_t find_tree_dqentry(struct qtree_mem_dqinfo *info, 571884d179dSJan Kara struct dquot *dquot, uint blk, int depth) 572884d179dSJan Kara { 573d26ac1a8SJan Kara char *buf = getdqbuf(info->dqi_usable_bs); 574884d179dSJan Kara loff_t ret = 0; 575884d179dSJan Kara __le32 *ref = (__le32 *)buf; 576884d179dSJan Kara 577884d179dSJan Kara if (!buf) 578884d179dSJan Kara return -ENOMEM; 579884d179dSJan Kara ret = read_blk(info, blk, buf); 580884d179dSJan Kara if (ret < 0) { 581fb5ffb0eSJiaying Zhang quota_error(dquot->dq_sb, "Can't read quota tree block %u", 582fb5ffb0eSJiaying Zhang blk); 583884d179dSJan Kara goto out_buf; 584884d179dSJan Kara } 585884d179dSJan Kara ret = 0; 586884d179dSJan Kara blk = le32_to_cpu(ref[get_index(info, dquot->dq_id, depth)]); 587884d179dSJan Kara if (!blk) /* No reference? */ 588884d179dSJan Kara goto out_buf; 589884d179dSJan Kara if (depth < info->dqi_qtree_depth - 1) 590884d179dSJan Kara ret = find_tree_dqentry(info, dquot, blk, depth+1); 591884d179dSJan Kara else 592884d179dSJan Kara ret = find_block_dqentry(info, dquot, blk); 593884d179dSJan Kara out_buf: 594d26ac1a8SJan Kara kfree(buf); 595884d179dSJan Kara return ret; 596884d179dSJan Kara } 597884d179dSJan Kara 598884d179dSJan Kara /* Find entry for given id in the tree - wrapper function */ 599884d179dSJan Kara static inline loff_t find_dqentry(struct qtree_mem_dqinfo *info, 600884d179dSJan Kara struct dquot *dquot) 601884d179dSJan Kara { 602884d179dSJan Kara return find_tree_dqentry(info, dquot, QT_TREEOFF, 0); 603884d179dSJan Kara } 604884d179dSJan Kara 605884d179dSJan Kara int qtree_read_dquot(struct qtree_mem_dqinfo *info, struct dquot *dquot) 606884d179dSJan Kara { 6074c376dcaSEric W. Biederman int type = dquot->dq_id.type; 608884d179dSJan Kara struct super_block *sb = dquot->dq_sb; 609884d179dSJan Kara loff_t offset; 610d26ac1a8SJan Kara char *ddquot; 611884d179dSJan Kara int ret = 0; 612884d179dSJan Kara 613884d179dSJan Kara #ifdef __QUOTA_QT_PARANOIA 614884d179dSJan Kara /* Invalidated quota? */ 615884d179dSJan Kara if (!sb_dqopt(dquot->dq_sb)->files[type]) { 616fb5ffb0eSJiaying Zhang quota_error(sb, "Quota invalidated while reading!"); 617884d179dSJan Kara return -EIO; 618884d179dSJan Kara } 619884d179dSJan Kara #endif 620884d179dSJan Kara /* Do we know offset of the dquot entry in the quota file? */ 621884d179dSJan Kara if (!dquot->dq_off) { 622884d179dSJan Kara offset = find_dqentry(info, dquot); 623884d179dSJan Kara if (offset <= 0) { /* Entry not present? */ 624884d179dSJan Kara if (offset < 0) 625fb5ffb0eSJiaying Zhang quota_error(sb,"Can't read quota structure " 6264c376dcaSEric W. Biederman "for id %u", 6274c376dcaSEric W. Biederman from_kqid(&init_user_ns, 6284c376dcaSEric W. Biederman dquot->dq_id)); 629884d179dSJan Kara dquot->dq_off = 0; 630884d179dSJan Kara set_bit(DQ_FAKE_B, &dquot->dq_flags); 631884d179dSJan Kara memset(&dquot->dq_dqb, 0, sizeof(struct mem_dqblk)); 632884d179dSJan Kara ret = offset; 633884d179dSJan Kara goto out; 634884d179dSJan Kara } 635884d179dSJan Kara dquot->dq_off = offset; 636884d179dSJan Kara } 637884d179dSJan Kara ddquot = getdqbuf(info->dqi_entry_size); 638884d179dSJan Kara if (!ddquot) 639884d179dSJan Kara return -ENOMEM; 640d26ac1a8SJan Kara ret = sb->s_op->quota_read(sb, type, ddquot, info->dqi_entry_size, 641d26ac1a8SJan Kara dquot->dq_off); 642884d179dSJan Kara if (ret != info->dqi_entry_size) { 643884d179dSJan Kara if (ret >= 0) 644884d179dSJan Kara ret = -EIO; 645fb5ffb0eSJiaying Zhang quota_error(sb, "Error while reading quota structure for id %u", 6464c376dcaSEric W. Biederman from_kqid(&init_user_ns, dquot->dq_id)); 647884d179dSJan Kara set_bit(DQ_FAKE_B, &dquot->dq_flags); 648884d179dSJan Kara memset(&dquot->dq_dqb, 0, sizeof(struct mem_dqblk)); 649d26ac1a8SJan Kara kfree(ddquot); 650884d179dSJan Kara goto out; 651884d179dSJan Kara } 652884d179dSJan Kara spin_lock(&dq_data_lock); 653884d179dSJan Kara info->dqi_ops->disk2mem_dqblk(dquot, ddquot); 654884d179dSJan Kara if (!dquot->dq_dqb.dqb_bhardlimit && 655884d179dSJan Kara !dquot->dq_dqb.dqb_bsoftlimit && 656884d179dSJan Kara !dquot->dq_dqb.dqb_ihardlimit && 657884d179dSJan Kara !dquot->dq_dqb.dqb_isoftlimit) 658884d179dSJan Kara set_bit(DQ_FAKE_B, &dquot->dq_flags); 659884d179dSJan Kara spin_unlock(&dq_data_lock); 660d26ac1a8SJan Kara kfree(ddquot); 661884d179dSJan Kara out: 662dde95888SDmitry Monakhov dqstats_inc(DQST_READS); 663884d179dSJan Kara return ret; 664884d179dSJan Kara } 665884d179dSJan Kara EXPORT_SYMBOL(qtree_read_dquot); 666884d179dSJan Kara 667884d179dSJan Kara /* Check whether dquot should not be deleted. We know we are 668884d179dSJan Kara * the only one operating on dquot (thanks to dq_lock) */ 669884d179dSJan Kara int qtree_release_dquot(struct qtree_mem_dqinfo *info, struct dquot *dquot) 670884d179dSJan Kara { 671268157baSJan Kara if (test_bit(DQ_FAKE_B, &dquot->dq_flags) && 672268157baSJan Kara !(dquot->dq_dqb.dqb_curinodes | dquot->dq_dqb.dqb_curspace)) 673884d179dSJan Kara return qtree_delete_dquot(info, dquot); 674884d179dSJan Kara return 0; 675884d179dSJan Kara } 676884d179dSJan Kara EXPORT_SYMBOL(qtree_release_dquot); 677*0066373dSJan Kara 678*0066373dSJan Kara static int find_next_id(struct qtree_mem_dqinfo *info, qid_t *id, 679*0066373dSJan Kara unsigned int blk, int depth) 680*0066373dSJan Kara { 681*0066373dSJan Kara char *buf = getdqbuf(info->dqi_usable_bs); 682*0066373dSJan Kara __le32 *ref = (__le32 *)buf; 683*0066373dSJan Kara ssize_t ret; 684*0066373dSJan Kara unsigned int epb = info->dqi_usable_bs >> 2; 685*0066373dSJan Kara unsigned int level_inc = 1; 686*0066373dSJan Kara int i; 687*0066373dSJan Kara 688*0066373dSJan Kara if (!buf) 689*0066373dSJan Kara return -ENOMEM; 690*0066373dSJan Kara 691*0066373dSJan Kara for (i = depth; i < info->dqi_qtree_depth - 1; i++) 692*0066373dSJan Kara level_inc *= epb; 693*0066373dSJan Kara 694*0066373dSJan Kara ret = read_blk(info, blk, buf); 695*0066373dSJan Kara if (ret < 0) { 696*0066373dSJan Kara quota_error(info->dqi_sb, 697*0066373dSJan Kara "Can't read quota tree block %u", blk); 698*0066373dSJan Kara goto out_buf; 699*0066373dSJan Kara } 700*0066373dSJan Kara for (i = __get_index(info, *id, depth); i < epb; i++) { 701*0066373dSJan Kara if (ref[i] == cpu_to_le32(0)) { 702*0066373dSJan Kara *id += level_inc; 703*0066373dSJan Kara continue; 704*0066373dSJan Kara } 705*0066373dSJan Kara if (depth == info->dqi_qtree_depth - 1) { 706*0066373dSJan Kara ret = 0; 707*0066373dSJan Kara goto out_buf; 708*0066373dSJan Kara } 709*0066373dSJan Kara ret = find_next_id(info, id, le32_to_cpu(ref[i]), depth + 1); 710*0066373dSJan Kara if (ret != -ENOENT) 711*0066373dSJan Kara break; 712*0066373dSJan Kara } 713*0066373dSJan Kara if (i == epb) { 714*0066373dSJan Kara ret = -ENOENT; 715*0066373dSJan Kara goto out_buf; 716*0066373dSJan Kara } 717*0066373dSJan Kara out_buf: 718*0066373dSJan Kara kfree(buf); 719*0066373dSJan Kara return ret; 720*0066373dSJan Kara } 721*0066373dSJan Kara 722*0066373dSJan Kara int qtree_get_next_id(struct qtree_mem_dqinfo *info, struct kqid *qid) 723*0066373dSJan Kara { 724*0066373dSJan Kara qid_t id = from_kqid(&init_user_ns, *qid); 725*0066373dSJan Kara int ret; 726*0066373dSJan Kara 727*0066373dSJan Kara ret = find_next_id(info, &id, QT_TREEOFF, 0); 728*0066373dSJan Kara if (ret < 0) 729*0066373dSJan Kara return ret; 730*0066373dSJan Kara *qid = make_kqid(&init_user_ns, qid->type, id); 731*0066373dSJan Kara return 0; 732*0066373dSJan Kara } 733*0066373dSJan Kara EXPORT_SYMBOL(qtree_get_next_id); 734