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 25884d179dSJan 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 35884d179dSJan Kara /* Number of entries in one blocks */ 36*7a2435d8SJan Kara static int qtree_dqstr_in_blk(struct qtree_mem_dqinfo *info) 37884d179dSJan Kara { 38884d179dSJan Kara return (info->dqi_usable_bs - sizeof(struct qt_disk_dqdbheader)) 39884d179dSJan Kara / info->dqi_entry_size; 40884d179dSJan Kara } 41884d179dSJan Kara 42d26ac1a8SJan Kara static char *getdqbuf(size_t size) 43884d179dSJan Kara { 44d26ac1a8SJan Kara char *buf = kmalloc(size, GFP_NOFS); 45884d179dSJan Kara if (!buf) 46884d179dSJan Kara printk(KERN_WARNING "VFS: Not enough memory for quota buffers.\n"); 47884d179dSJan Kara return buf; 48884d179dSJan Kara } 49884d179dSJan Kara 50*7a2435d8SJan 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, 56884d179dSJan Kara info->dqi_usable_bs, blk << info->dqi_blocksize_bits); 57884d179dSJan Kara } 58884d179dSJan Kara 59*7a2435d8SJan 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; 62884d179dSJan Kara 63d26ac1a8SJan Kara return sb->s_op->quota_write(sb, info->dqi_type, buf, 64884d179dSJan Kara info->dqi_usable_bs, blk << info->dqi_blocksize_bits); 65884d179dSJan Kara } 66884d179dSJan Kara 67884d179dSJan Kara /* Remove empty block from list and return it */ 68884d179dSJan Kara static int get_free_dqblk(struct qtree_mem_dqinfo *info) 69884d179dSJan Kara { 70d26ac1a8SJan Kara char *buf = getdqbuf(info->dqi_usable_bs); 71884d179dSJan Kara struct qt_disk_dqdbheader *dh = (struct qt_disk_dqdbheader *)buf; 72884d179dSJan Kara int ret, blk; 73884d179dSJan Kara 74884d179dSJan Kara if (!buf) 75884d179dSJan Kara return -ENOMEM; 76884d179dSJan Kara if (info->dqi_free_blk) { 77884d179dSJan Kara blk = info->dqi_free_blk; 78884d179dSJan Kara ret = read_blk(info, blk, buf); 79884d179dSJan Kara if (ret < 0) 80884d179dSJan Kara goto out_buf; 81884d179dSJan Kara info->dqi_free_blk = le32_to_cpu(dh->dqdh_next_free); 82884d179dSJan Kara } 83884d179dSJan Kara else { 84884d179dSJan Kara memset(buf, 0, info->dqi_usable_bs); 85884d179dSJan Kara /* Assure block allocation... */ 86884d179dSJan Kara ret = write_blk(info, info->dqi_blocks, buf); 87884d179dSJan Kara if (ret < 0) 88884d179dSJan Kara goto out_buf; 89884d179dSJan Kara blk = info->dqi_blocks++; 90884d179dSJan Kara } 91884d179dSJan Kara mark_info_dirty(info->dqi_sb, info->dqi_type); 92884d179dSJan Kara ret = blk; 93884d179dSJan Kara out_buf: 94d26ac1a8SJan Kara kfree(buf); 95884d179dSJan Kara return ret; 96884d179dSJan Kara } 97884d179dSJan Kara 98884d179dSJan Kara /* Insert empty block to the list */ 99d26ac1a8SJan Kara static int put_free_dqblk(struct qtree_mem_dqinfo *info, char *buf, uint blk) 100884d179dSJan Kara { 101884d179dSJan Kara struct qt_disk_dqdbheader *dh = (struct qt_disk_dqdbheader *)buf; 102884d179dSJan Kara int err; 103884d179dSJan Kara 104884d179dSJan Kara dh->dqdh_next_free = cpu_to_le32(info->dqi_free_blk); 105884d179dSJan Kara dh->dqdh_prev_free = cpu_to_le32(0); 106884d179dSJan Kara dh->dqdh_entries = cpu_to_le16(0); 107884d179dSJan Kara err = write_blk(info, blk, buf); 108884d179dSJan Kara if (err < 0) 109884d179dSJan Kara return err; 110884d179dSJan Kara info->dqi_free_blk = blk; 111884d179dSJan Kara mark_info_dirty(info->dqi_sb, info->dqi_type); 112884d179dSJan Kara return 0; 113884d179dSJan Kara } 114884d179dSJan Kara 115884d179dSJan Kara /* Remove given block from the list of blocks with free entries */ 116d26ac1a8SJan Kara static int remove_free_dqentry(struct qtree_mem_dqinfo *info, char *buf, uint blk) 117884d179dSJan Kara { 118d26ac1a8SJan Kara char *tmpbuf = getdqbuf(info->dqi_usable_bs); 119884d179dSJan Kara struct qt_disk_dqdbheader *dh = (struct qt_disk_dqdbheader *)buf; 120884d179dSJan Kara uint nextblk = le32_to_cpu(dh->dqdh_next_free); 121884d179dSJan Kara uint prevblk = le32_to_cpu(dh->dqdh_prev_free); 122884d179dSJan Kara int err; 123884d179dSJan Kara 124884d179dSJan Kara if (!tmpbuf) 125884d179dSJan Kara return -ENOMEM; 126884d179dSJan Kara if (nextblk) { 127884d179dSJan Kara err = read_blk(info, nextblk, tmpbuf); 128884d179dSJan Kara if (err < 0) 129884d179dSJan Kara goto out_buf; 130884d179dSJan Kara ((struct qt_disk_dqdbheader *)tmpbuf)->dqdh_prev_free = 131884d179dSJan Kara dh->dqdh_prev_free; 132884d179dSJan Kara err = write_blk(info, nextblk, tmpbuf); 133884d179dSJan Kara if (err < 0) 134884d179dSJan Kara goto out_buf; 135884d179dSJan Kara } 136884d179dSJan Kara if (prevblk) { 137884d179dSJan Kara err = read_blk(info, prevblk, tmpbuf); 138884d179dSJan Kara if (err < 0) 139884d179dSJan Kara goto out_buf; 140884d179dSJan Kara ((struct qt_disk_dqdbheader *)tmpbuf)->dqdh_next_free = 141884d179dSJan Kara dh->dqdh_next_free; 142884d179dSJan Kara err = write_blk(info, prevblk, tmpbuf); 143884d179dSJan Kara if (err < 0) 144884d179dSJan Kara goto out_buf; 145884d179dSJan Kara } else { 146884d179dSJan Kara info->dqi_free_entry = nextblk; 147884d179dSJan Kara mark_info_dirty(info->dqi_sb, info->dqi_type); 148884d179dSJan Kara } 149d26ac1a8SJan Kara kfree(tmpbuf); 150884d179dSJan Kara dh->dqdh_next_free = dh->dqdh_prev_free = cpu_to_le32(0); 151884d179dSJan Kara /* No matter whether write succeeds block is out of list */ 152884d179dSJan Kara if (write_blk(info, blk, buf) < 0) 153884d179dSJan Kara printk(KERN_ERR "VFS: Can't write block (%u) with free entries.\n", blk); 154884d179dSJan Kara return 0; 155884d179dSJan Kara out_buf: 156d26ac1a8SJan Kara kfree(tmpbuf); 157884d179dSJan Kara return err; 158884d179dSJan Kara } 159884d179dSJan Kara 160884d179dSJan Kara /* Insert given block to the beginning of list with free entries */ 161d26ac1a8SJan Kara static int insert_free_dqentry(struct qtree_mem_dqinfo *info, char *buf, uint blk) 162884d179dSJan Kara { 163d26ac1a8SJan Kara char *tmpbuf = getdqbuf(info->dqi_usable_bs); 164884d179dSJan Kara struct qt_disk_dqdbheader *dh = (struct qt_disk_dqdbheader *)buf; 165884d179dSJan Kara int err; 166884d179dSJan Kara 167884d179dSJan Kara if (!tmpbuf) 168884d179dSJan Kara return -ENOMEM; 169884d179dSJan Kara dh->dqdh_next_free = cpu_to_le32(info->dqi_free_entry); 170884d179dSJan Kara dh->dqdh_prev_free = cpu_to_le32(0); 171884d179dSJan Kara err = write_blk(info, blk, buf); 172884d179dSJan Kara if (err < 0) 173884d179dSJan Kara goto out_buf; 174884d179dSJan Kara if (info->dqi_free_entry) { 175884d179dSJan Kara err = read_blk(info, info->dqi_free_entry, tmpbuf); 176884d179dSJan Kara if (err < 0) 177884d179dSJan Kara goto out_buf; 178884d179dSJan Kara ((struct qt_disk_dqdbheader *)tmpbuf)->dqdh_prev_free = 179884d179dSJan Kara cpu_to_le32(blk); 180884d179dSJan Kara err = write_blk(info, info->dqi_free_entry, tmpbuf); 181884d179dSJan Kara if (err < 0) 182884d179dSJan Kara goto out_buf; 183884d179dSJan Kara } 184d26ac1a8SJan Kara kfree(tmpbuf); 185884d179dSJan Kara info->dqi_free_entry = blk; 186884d179dSJan Kara mark_info_dirty(info->dqi_sb, info->dqi_type); 187884d179dSJan Kara return 0; 188884d179dSJan Kara out_buf: 189d26ac1a8SJan Kara kfree(tmpbuf); 190884d179dSJan Kara return err; 191884d179dSJan Kara } 192884d179dSJan Kara 193884d179dSJan Kara /* Is the entry in the block free? */ 194884d179dSJan Kara int qtree_entry_unused(struct qtree_mem_dqinfo *info, char *disk) 195884d179dSJan Kara { 196884d179dSJan Kara int i; 197884d179dSJan Kara 198884d179dSJan Kara for (i = 0; i < info->dqi_entry_size; i++) 199884d179dSJan Kara if (disk[i]) 200884d179dSJan Kara return 0; 201884d179dSJan Kara return 1; 202884d179dSJan Kara } 203884d179dSJan Kara EXPORT_SYMBOL(qtree_entry_unused); 204884d179dSJan Kara 205884d179dSJan Kara /* Find space for dquot */ 206884d179dSJan Kara static uint find_free_dqentry(struct qtree_mem_dqinfo *info, 207884d179dSJan Kara struct dquot *dquot, int *err) 208884d179dSJan Kara { 209884d179dSJan Kara uint blk, i; 210884d179dSJan Kara struct qt_disk_dqdbheader *dh; 211d26ac1a8SJan Kara char *buf = getdqbuf(info->dqi_usable_bs); 212884d179dSJan Kara char *ddquot; 213884d179dSJan Kara 214884d179dSJan Kara *err = 0; 215884d179dSJan Kara if (!buf) { 216884d179dSJan Kara *err = -ENOMEM; 217884d179dSJan Kara return 0; 218884d179dSJan Kara } 219884d179dSJan Kara dh = (struct qt_disk_dqdbheader *)buf; 220884d179dSJan Kara if (info->dqi_free_entry) { 221884d179dSJan Kara blk = info->dqi_free_entry; 222884d179dSJan Kara *err = read_blk(info, blk, buf); 223884d179dSJan Kara if (*err < 0) 224884d179dSJan Kara goto out_buf; 225884d179dSJan Kara } else { 226884d179dSJan Kara blk = get_free_dqblk(info); 227884d179dSJan Kara if ((int)blk < 0) { 228884d179dSJan Kara *err = blk; 229d26ac1a8SJan Kara kfree(buf); 230884d179dSJan Kara return 0; 231884d179dSJan Kara } 232884d179dSJan Kara memset(buf, 0, info->dqi_usable_bs); 233884d179dSJan Kara /* This is enough as block is already zeroed and entry list is empty... */ 234884d179dSJan Kara info->dqi_free_entry = blk; 235884d179dSJan Kara mark_info_dirty(dquot->dq_sb, dquot->dq_type); 236884d179dSJan Kara } 237884d179dSJan Kara /* Block will be full? */ 238884d179dSJan Kara if (le16_to_cpu(dh->dqdh_entries) + 1 >= qtree_dqstr_in_blk(info)) { 239884d179dSJan Kara *err = remove_free_dqentry(info, buf, blk); 240884d179dSJan Kara if (*err < 0) { 241884d179dSJan Kara printk(KERN_ERR "VFS: find_free_dqentry(): Can't " 242884d179dSJan Kara "remove block (%u) from entry free list.\n", 243884d179dSJan Kara blk); 244884d179dSJan Kara goto out_buf; 245884d179dSJan Kara } 246884d179dSJan Kara } 247884d179dSJan Kara le16_add_cpu(&dh->dqdh_entries, 1); 248884d179dSJan Kara /* Find free structure in block */ 249d26ac1a8SJan Kara for (i = 0, ddquot = buf + sizeof(struct qt_disk_dqdbheader); 250884d179dSJan Kara i < qtree_dqstr_in_blk(info) && !qtree_entry_unused(info, ddquot); 251d26ac1a8SJan Kara i++, ddquot += info->dqi_entry_size) 252d26ac1a8SJan Kara ; 253884d179dSJan Kara #ifdef __QUOTA_QT_PARANOIA 254884d179dSJan Kara if (i == qtree_dqstr_in_blk(info)) { 255884d179dSJan Kara printk(KERN_ERR "VFS: find_free_dqentry(): Data block full " 256884d179dSJan Kara "but it shouldn't.\n"); 257884d179dSJan Kara *err = -EIO; 258884d179dSJan Kara goto out_buf; 259884d179dSJan Kara } 260884d179dSJan Kara #endif 261884d179dSJan Kara *err = write_blk(info, blk, buf); 262884d179dSJan Kara if (*err < 0) { 263884d179dSJan Kara printk(KERN_ERR "VFS: find_free_dqentry(): Can't write quota " 264884d179dSJan Kara "data block %u.\n", blk); 265884d179dSJan Kara goto out_buf; 266884d179dSJan Kara } 267884d179dSJan Kara dquot->dq_off = (blk << info->dqi_blocksize_bits) + 268884d179dSJan Kara sizeof(struct qt_disk_dqdbheader) + 269884d179dSJan Kara i * info->dqi_entry_size; 270d26ac1a8SJan Kara kfree(buf); 271884d179dSJan Kara return blk; 272884d179dSJan Kara out_buf: 273d26ac1a8SJan Kara kfree(buf); 274884d179dSJan Kara return 0; 275884d179dSJan Kara } 276884d179dSJan Kara 277884d179dSJan Kara /* Insert reference to structure into the trie */ 278884d179dSJan Kara static int do_insert_tree(struct qtree_mem_dqinfo *info, struct dquot *dquot, 279884d179dSJan Kara uint *treeblk, int depth) 280884d179dSJan Kara { 281d26ac1a8SJan Kara char *buf = getdqbuf(info->dqi_usable_bs); 282884d179dSJan Kara int ret = 0, newson = 0, newact = 0; 283884d179dSJan Kara __le32 *ref; 284884d179dSJan Kara uint newblk; 285884d179dSJan Kara 286884d179dSJan Kara if (!buf) 287884d179dSJan Kara return -ENOMEM; 288884d179dSJan Kara if (!*treeblk) { 289884d179dSJan Kara ret = get_free_dqblk(info); 290884d179dSJan Kara if (ret < 0) 291884d179dSJan Kara goto out_buf; 292884d179dSJan Kara *treeblk = ret; 293884d179dSJan Kara memset(buf, 0, info->dqi_usable_bs); 294884d179dSJan Kara newact = 1; 295884d179dSJan Kara } else { 296884d179dSJan Kara ret = read_blk(info, *treeblk, buf); 297884d179dSJan Kara if (ret < 0) { 298884d179dSJan Kara printk(KERN_ERR "VFS: Can't read tree quota block " 299884d179dSJan Kara "%u.\n", *treeblk); 300884d179dSJan Kara goto out_buf; 301884d179dSJan Kara } 302884d179dSJan Kara } 303884d179dSJan Kara ref = (__le32 *)buf; 304884d179dSJan Kara newblk = le32_to_cpu(ref[get_index(info, dquot->dq_id, depth)]); 305884d179dSJan Kara if (!newblk) 306884d179dSJan Kara newson = 1; 307884d179dSJan Kara if (depth == info->dqi_qtree_depth - 1) { 308884d179dSJan Kara #ifdef __QUOTA_QT_PARANOIA 309884d179dSJan Kara if (newblk) { 310884d179dSJan Kara printk(KERN_ERR "VFS: Inserting already present quota " 311884d179dSJan Kara "entry (block %u).\n", 312884d179dSJan Kara le32_to_cpu(ref[get_index(info, 313884d179dSJan Kara dquot->dq_id, depth)])); 314884d179dSJan Kara ret = -EIO; 315884d179dSJan Kara goto out_buf; 316884d179dSJan Kara } 317884d179dSJan Kara #endif 318884d179dSJan Kara newblk = find_free_dqentry(info, dquot, &ret); 319884d179dSJan Kara } else { 320884d179dSJan Kara ret = do_insert_tree(info, dquot, &newblk, depth+1); 321884d179dSJan Kara } 322884d179dSJan Kara if (newson && ret >= 0) { 323884d179dSJan Kara ref[get_index(info, dquot->dq_id, depth)] = 324884d179dSJan Kara cpu_to_le32(newblk); 325884d179dSJan Kara ret = write_blk(info, *treeblk, buf); 326884d179dSJan Kara } else if (newact && ret < 0) { 327884d179dSJan Kara put_free_dqblk(info, buf, *treeblk); 328884d179dSJan Kara } 329884d179dSJan Kara out_buf: 330d26ac1a8SJan Kara kfree(buf); 331884d179dSJan Kara return ret; 332884d179dSJan Kara } 333884d179dSJan Kara 334884d179dSJan Kara /* Wrapper for inserting quota structure into tree */ 335884d179dSJan Kara static inline int dq_insert_tree(struct qtree_mem_dqinfo *info, 336884d179dSJan Kara struct dquot *dquot) 337884d179dSJan Kara { 338884d179dSJan Kara int tmp = QT_TREEOFF; 339884d179dSJan Kara return do_insert_tree(info, dquot, &tmp, 0); 340884d179dSJan Kara } 341884d179dSJan Kara 342884d179dSJan Kara /* 343884d179dSJan Kara * We don't have to be afraid of deadlocks as we never have quotas on quota files... 344884d179dSJan Kara */ 345884d179dSJan Kara int qtree_write_dquot(struct qtree_mem_dqinfo *info, struct dquot *dquot) 346884d179dSJan Kara { 347884d179dSJan Kara int type = dquot->dq_type; 348884d179dSJan Kara struct super_block *sb = dquot->dq_sb; 349884d179dSJan Kara ssize_t ret; 350d26ac1a8SJan Kara char *ddquot = getdqbuf(info->dqi_entry_size); 351884d179dSJan Kara 352884d179dSJan Kara if (!ddquot) 353884d179dSJan Kara return -ENOMEM; 354884d179dSJan Kara 355884d179dSJan Kara /* dq_off is guarded by dqio_mutex */ 356884d179dSJan Kara if (!dquot->dq_off) { 357884d179dSJan Kara ret = dq_insert_tree(info, dquot); 358884d179dSJan Kara if (ret < 0) { 359884d179dSJan Kara printk(KERN_ERR "VFS: Error %zd occurred while " 360884d179dSJan Kara "creating quota.\n", ret); 361d26ac1a8SJan Kara kfree(ddquot); 362884d179dSJan Kara return ret; 363884d179dSJan Kara } 364884d179dSJan Kara } 365884d179dSJan Kara spin_lock(&dq_data_lock); 366884d179dSJan Kara info->dqi_ops->mem2disk_dqblk(ddquot, dquot); 367884d179dSJan Kara spin_unlock(&dq_data_lock); 368d26ac1a8SJan Kara ret = sb->s_op->quota_write(sb, type, ddquot, info->dqi_entry_size, 369d26ac1a8SJan Kara dquot->dq_off); 370884d179dSJan Kara if (ret != info->dqi_entry_size) { 371884d179dSJan Kara printk(KERN_WARNING "VFS: dquota write failed on dev %s\n", 372884d179dSJan Kara sb->s_id); 373884d179dSJan Kara if (ret >= 0) 374884d179dSJan Kara ret = -ENOSPC; 375884d179dSJan Kara } else { 376884d179dSJan Kara ret = 0; 377884d179dSJan Kara } 378884d179dSJan Kara dqstats.writes++; 379d26ac1a8SJan Kara kfree(ddquot); 380884d179dSJan Kara 381884d179dSJan Kara return ret; 382884d179dSJan Kara } 383884d179dSJan Kara EXPORT_SYMBOL(qtree_write_dquot); 384884d179dSJan Kara 385884d179dSJan Kara /* Free dquot entry in data block */ 386884d179dSJan Kara static int free_dqentry(struct qtree_mem_dqinfo *info, struct dquot *dquot, 387884d179dSJan Kara uint blk) 388884d179dSJan Kara { 389884d179dSJan Kara struct qt_disk_dqdbheader *dh; 390d26ac1a8SJan Kara char *buf = getdqbuf(info->dqi_usable_bs); 391884d179dSJan Kara int ret = 0; 392884d179dSJan Kara 393884d179dSJan Kara if (!buf) 394884d179dSJan Kara return -ENOMEM; 395884d179dSJan Kara if (dquot->dq_off >> info->dqi_blocksize_bits != blk) { 396884d179dSJan Kara printk(KERN_ERR "VFS: Quota structure has offset to other " 397884d179dSJan Kara "block (%u) than it should (%u).\n", blk, 398884d179dSJan Kara (uint)(dquot->dq_off >> info->dqi_blocksize_bits)); 399884d179dSJan Kara goto out_buf; 400884d179dSJan Kara } 401884d179dSJan Kara ret = read_blk(info, blk, buf); 402884d179dSJan Kara if (ret < 0) { 403884d179dSJan Kara printk(KERN_ERR "VFS: Can't read quota data block %u\n", blk); 404884d179dSJan Kara goto out_buf; 405884d179dSJan Kara } 406884d179dSJan Kara dh = (struct qt_disk_dqdbheader *)buf; 407884d179dSJan Kara le16_add_cpu(&dh->dqdh_entries, -1); 408884d179dSJan Kara if (!le16_to_cpu(dh->dqdh_entries)) { /* Block got free? */ 409884d179dSJan Kara ret = remove_free_dqentry(info, buf, blk); 410884d179dSJan Kara if (ret >= 0) 411884d179dSJan Kara ret = put_free_dqblk(info, buf, blk); 412884d179dSJan Kara if (ret < 0) { 413884d179dSJan Kara printk(KERN_ERR "VFS: Can't move quota data block (%u) " 414884d179dSJan Kara "to free list.\n", blk); 415884d179dSJan Kara goto out_buf; 416884d179dSJan Kara } 417884d179dSJan Kara } else { 418884d179dSJan Kara memset(buf + 419884d179dSJan Kara (dquot->dq_off & ((1 << info->dqi_blocksize_bits) - 1)), 420884d179dSJan Kara 0, info->dqi_entry_size); 421884d179dSJan Kara if (le16_to_cpu(dh->dqdh_entries) == 422884d179dSJan Kara qtree_dqstr_in_blk(info) - 1) { 423884d179dSJan Kara /* Insert will write block itself */ 424884d179dSJan Kara ret = insert_free_dqentry(info, buf, blk); 425884d179dSJan Kara if (ret < 0) { 426884d179dSJan Kara printk(KERN_ERR "VFS: Can't insert quota data " 427884d179dSJan Kara "block (%u) to free entry list.\n", blk); 428884d179dSJan Kara goto out_buf; 429884d179dSJan Kara } 430884d179dSJan Kara } else { 431884d179dSJan Kara ret = write_blk(info, blk, buf); 432884d179dSJan Kara if (ret < 0) { 433884d179dSJan Kara printk(KERN_ERR "VFS: Can't write quota data " 434884d179dSJan Kara "block %u\n", blk); 435884d179dSJan Kara goto out_buf; 436884d179dSJan Kara } 437884d179dSJan Kara } 438884d179dSJan Kara } 439884d179dSJan Kara dquot->dq_off = 0; /* Quota is now unattached */ 440884d179dSJan Kara out_buf: 441d26ac1a8SJan Kara kfree(buf); 442884d179dSJan Kara return ret; 443884d179dSJan Kara } 444884d179dSJan Kara 445884d179dSJan Kara /* Remove reference to dquot from tree */ 446884d179dSJan Kara static int remove_tree(struct qtree_mem_dqinfo *info, struct dquot *dquot, 447884d179dSJan Kara uint *blk, int depth) 448884d179dSJan Kara { 449d26ac1a8SJan Kara char *buf = getdqbuf(info->dqi_usable_bs); 450884d179dSJan Kara int ret = 0; 451884d179dSJan Kara uint newblk; 452884d179dSJan Kara __le32 *ref = (__le32 *)buf; 453884d179dSJan Kara 454884d179dSJan Kara if (!buf) 455884d179dSJan Kara return -ENOMEM; 456884d179dSJan Kara ret = read_blk(info, *blk, buf); 457884d179dSJan Kara if (ret < 0) { 458884d179dSJan Kara printk(KERN_ERR "VFS: Can't read quota data block %u\n", *blk); 459884d179dSJan Kara goto out_buf; 460884d179dSJan Kara } 461884d179dSJan Kara newblk = le32_to_cpu(ref[get_index(info, dquot->dq_id, depth)]); 462884d179dSJan Kara if (depth == info->dqi_qtree_depth - 1) { 463884d179dSJan Kara ret = free_dqentry(info, dquot, newblk); 464884d179dSJan Kara newblk = 0; 465884d179dSJan Kara } else { 466884d179dSJan Kara ret = remove_tree(info, dquot, &newblk, depth+1); 467884d179dSJan Kara } 468884d179dSJan Kara if (ret >= 0 && !newblk) { 469884d179dSJan Kara int i; 470884d179dSJan Kara ref[get_index(info, dquot->dq_id, depth)] = cpu_to_le32(0); 471884d179dSJan Kara /* Block got empty? */ 472d26ac1a8SJan Kara for (i = 0; i < (info->dqi_usable_bs >> 2) && !ref[i]; i++) 473d26ac1a8SJan Kara ; 474884d179dSJan Kara /* Don't put the root block into the free block list */ 475884d179dSJan Kara if (i == (info->dqi_usable_bs >> 2) 476884d179dSJan Kara && *blk != QT_TREEOFF) { 477884d179dSJan Kara put_free_dqblk(info, buf, *blk); 478884d179dSJan Kara *blk = 0; 479884d179dSJan Kara } else { 480884d179dSJan Kara ret = write_blk(info, *blk, buf); 481884d179dSJan Kara if (ret < 0) 482884d179dSJan Kara printk(KERN_ERR "VFS: Can't write quota tree " 483884d179dSJan Kara "block %u.\n", *blk); 484884d179dSJan Kara } 485884d179dSJan Kara } 486884d179dSJan Kara out_buf: 487d26ac1a8SJan Kara kfree(buf); 488884d179dSJan Kara return ret; 489884d179dSJan Kara } 490884d179dSJan Kara 491884d179dSJan Kara /* Delete dquot from tree */ 492884d179dSJan Kara int qtree_delete_dquot(struct qtree_mem_dqinfo *info, struct dquot *dquot) 493884d179dSJan Kara { 494884d179dSJan Kara uint tmp = QT_TREEOFF; 495884d179dSJan Kara 496884d179dSJan Kara if (!dquot->dq_off) /* Even not allocated? */ 497884d179dSJan Kara return 0; 498884d179dSJan Kara return remove_tree(info, dquot, &tmp, 0); 499884d179dSJan Kara } 500884d179dSJan Kara EXPORT_SYMBOL(qtree_delete_dquot); 501884d179dSJan Kara 502884d179dSJan Kara /* Find entry in block */ 503884d179dSJan Kara static loff_t find_block_dqentry(struct qtree_mem_dqinfo *info, 504884d179dSJan Kara struct dquot *dquot, uint blk) 505884d179dSJan Kara { 506d26ac1a8SJan Kara char *buf = getdqbuf(info->dqi_usable_bs); 507884d179dSJan Kara loff_t ret = 0; 508884d179dSJan Kara int i; 509884d179dSJan Kara char *ddquot; 510884d179dSJan Kara 511884d179dSJan Kara if (!buf) 512884d179dSJan Kara return -ENOMEM; 513884d179dSJan Kara ret = read_blk(info, blk, buf); 514884d179dSJan Kara if (ret < 0) { 515884d179dSJan Kara printk(KERN_ERR "VFS: Can't read quota tree block %u.\n", blk); 516884d179dSJan Kara goto out_buf; 517884d179dSJan Kara } 518d26ac1a8SJan Kara for (i = 0, ddquot = buf + sizeof(struct qt_disk_dqdbheader); 519884d179dSJan Kara i < qtree_dqstr_in_blk(info) && !info->dqi_ops->is_id(ddquot, dquot); 520d26ac1a8SJan Kara i++, ddquot += info->dqi_entry_size) 521d26ac1a8SJan Kara ; 522884d179dSJan Kara if (i == qtree_dqstr_in_blk(info)) { 523884d179dSJan Kara printk(KERN_ERR "VFS: Quota for id %u referenced " 524884d179dSJan Kara "but not present.\n", dquot->dq_id); 525884d179dSJan Kara ret = -EIO; 526884d179dSJan Kara goto out_buf; 527884d179dSJan Kara } else { 528884d179dSJan Kara ret = (blk << info->dqi_blocksize_bits) + sizeof(struct 529884d179dSJan Kara qt_disk_dqdbheader) + i * info->dqi_entry_size; 530884d179dSJan Kara } 531884d179dSJan Kara out_buf: 532d26ac1a8SJan Kara kfree(buf); 533884d179dSJan Kara return ret; 534884d179dSJan Kara } 535884d179dSJan Kara 536884d179dSJan Kara /* Find entry for given id in the tree */ 537884d179dSJan Kara static loff_t find_tree_dqentry(struct qtree_mem_dqinfo *info, 538884d179dSJan Kara struct dquot *dquot, uint blk, int depth) 539884d179dSJan Kara { 540d26ac1a8SJan Kara char *buf = getdqbuf(info->dqi_usable_bs); 541884d179dSJan Kara loff_t ret = 0; 542884d179dSJan Kara __le32 *ref = (__le32 *)buf; 543884d179dSJan Kara 544884d179dSJan Kara if (!buf) 545884d179dSJan Kara return -ENOMEM; 546884d179dSJan Kara ret = read_blk(info, blk, buf); 547884d179dSJan Kara if (ret < 0) { 548884d179dSJan Kara printk(KERN_ERR "VFS: Can't read quota tree block %u.\n", blk); 549884d179dSJan Kara goto out_buf; 550884d179dSJan Kara } 551884d179dSJan Kara ret = 0; 552884d179dSJan Kara blk = le32_to_cpu(ref[get_index(info, dquot->dq_id, depth)]); 553884d179dSJan Kara if (!blk) /* No reference? */ 554884d179dSJan Kara goto out_buf; 555884d179dSJan Kara if (depth < info->dqi_qtree_depth - 1) 556884d179dSJan Kara ret = find_tree_dqentry(info, dquot, blk, depth+1); 557884d179dSJan Kara else 558884d179dSJan Kara ret = find_block_dqentry(info, dquot, blk); 559884d179dSJan Kara out_buf: 560d26ac1a8SJan Kara kfree(buf); 561884d179dSJan Kara return ret; 562884d179dSJan Kara } 563884d179dSJan Kara 564884d179dSJan Kara /* Find entry for given id in the tree - wrapper function */ 565884d179dSJan Kara static inline loff_t find_dqentry(struct qtree_mem_dqinfo *info, 566884d179dSJan Kara struct dquot *dquot) 567884d179dSJan Kara { 568884d179dSJan Kara return find_tree_dqentry(info, dquot, QT_TREEOFF, 0); 569884d179dSJan Kara } 570884d179dSJan Kara 571884d179dSJan Kara int qtree_read_dquot(struct qtree_mem_dqinfo *info, struct dquot *dquot) 572884d179dSJan Kara { 573884d179dSJan Kara int type = dquot->dq_type; 574884d179dSJan Kara struct super_block *sb = dquot->dq_sb; 575884d179dSJan Kara loff_t offset; 576d26ac1a8SJan Kara char *ddquot; 577884d179dSJan Kara int ret = 0; 578884d179dSJan Kara 579884d179dSJan Kara #ifdef __QUOTA_QT_PARANOIA 580884d179dSJan Kara /* Invalidated quota? */ 581884d179dSJan Kara if (!sb_dqopt(dquot->dq_sb)->files[type]) { 582884d179dSJan Kara printk(KERN_ERR "VFS: Quota invalidated while reading!\n"); 583884d179dSJan Kara return -EIO; 584884d179dSJan Kara } 585884d179dSJan Kara #endif 586884d179dSJan Kara /* Do we know offset of the dquot entry in the quota file? */ 587884d179dSJan Kara if (!dquot->dq_off) { 588884d179dSJan Kara offset = find_dqentry(info, dquot); 589884d179dSJan Kara if (offset <= 0) { /* Entry not present? */ 590884d179dSJan Kara if (offset < 0) 591884d179dSJan Kara printk(KERN_ERR "VFS: Can't read quota " 592884d179dSJan Kara "structure for id %u.\n", dquot->dq_id); 593884d179dSJan Kara dquot->dq_off = 0; 594884d179dSJan Kara set_bit(DQ_FAKE_B, &dquot->dq_flags); 595884d179dSJan Kara memset(&dquot->dq_dqb, 0, sizeof(struct mem_dqblk)); 596884d179dSJan Kara ret = offset; 597884d179dSJan Kara goto out; 598884d179dSJan Kara } 599884d179dSJan Kara dquot->dq_off = offset; 600884d179dSJan Kara } 601884d179dSJan Kara ddquot = getdqbuf(info->dqi_entry_size); 602884d179dSJan Kara if (!ddquot) 603884d179dSJan Kara return -ENOMEM; 604d26ac1a8SJan Kara ret = sb->s_op->quota_read(sb, type, ddquot, info->dqi_entry_size, 605d26ac1a8SJan Kara dquot->dq_off); 606884d179dSJan Kara if (ret != info->dqi_entry_size) { 607884d179dSJan Kara if (ret >= 0) 608884d179dSJan Kara ret = -EIO; 609884d179dSJan Kara printk(KERN_ERR "VFS: Error while reading quota " 610884d179dSJan Kara "structure for id %u.\n", dquot->dq_id); 611884d179dSJan Kara set_bit(DQ_FAKE_B, &dquot->dq_flags); 612884d179dSJan Kara memset(&dquot->dq_dqb, 0, sizeof(struct mem_dqblk)); 613d26ac1a8SJan Kara kfree(ddquot); 614884d179dSJan Kara goto out; 615884d179dSJan Kara } 616884d179dSJan Kara spin_lock(&dq_data_lock); 617884d179dSJan Kara info->dqi_ops->disk2mem_dqblk(dquot, ddquot); 618884d179dSJan Kara if (!dquot->dq_dqb.dqb_bhardlimit && 619884d179dSJan Kara !dquot->dq_dqb.dqb_bsoftlimit && 620884d179dSJan Kara !dquot->dq_dqb.dqb_ihardlimit && 621884d179dSJan Kara !dquot->dq_dqb.dqb_isoftlimit) 622884d179dSJan Kara set_bit(DQ_FAKE_B, &dquot->dq_flags); 623884d179dSJan Kara spin_unlock(&dq_data_lock); 624d26ac1a8SJan Kara kfree(ddquot); 625884d179dSJan Kara out: 626884d179dSJan Kara dqstats.reads++; 627884d179dSJan Kara return ret; 628884d179dSJan Kara } 629884d179dSJan Kara EXPORT_SYMBOL(qtree_read_dquot); 630884d179dSJan Kara 631884d179dSJan Kara /* Check whether dquot should not be deleted. We know we are 632884d179dSJan Kara * the only one operating on dquot (thanks to dq_lock) */ 633884d179dSJan Kara int qtree_release_dquot(struct qtree_mem_dqinfo *info, struct dquot *dquot) 634884d179dSJan Kara { 635884d179dSJan Kara if (test_bit(DQ_FAKE_B, &dquot->dq_flags) && !(dquot->dq_dqb.dqb_curinodes | dquot->dq_dqb.dqb_curspace)) 636884d179dSJan Kara return qtree_delete_dquot(info, dquot); 637884d179dSJan Kara return 0; 638884d179dSJan Kara } 639884d179dSJan Kara EXPORT_SYMBOL(qtree_release_dquot); 640