1f239fefc14226f655477179801c734749a04d4b4Aditya Kali/* 2f239fefc14226f655477179801c734749a04d4b4Aditya Kali * mkquota.c --- create quota files for a filesystem 3f239fefc14226f655477179801c734749a04d4b4Aditya Kali * 4f239fefc14226f655477179801c734749a04d4b4Aditya Kali * Aditya Kali <adityakali@google.com> 5f239fefc14226f655477179801c734749a04d4b4Aditya Kali */ 6d1154eb460efe588eaed3d439c1caaca149fa362Theodore Ts'o#include "config.h" 7f239fefc14226f655477179801c734749a04d4b4Aditya Kali#include <sys/types.h> 8f239fefc14226f655477179801c734749a04d4b4Aditya Kali#include <sys/stat.h> 9f239fefc14226f655477179801c734749a04d4b4Aditya Kali#include <unistd.h> 10f239fefc14226f655477179801c734749a04d4b4Aditya Kali#include <errno.h> 11f239fefc14226f655477179801c734749a04d4b4Aditya Kali#include <string.h> 12f239fefc14226f655477179801c734749a04d4b4Aditya Kali#include <fcntl.h> 13f239fefc14226f655477179801c734749a04d4b4Aditya Kali 14f239fefc14226f655477179801c734749a04d4b4Aditya Kali#include "ext2fs/ext2_fs.h" 15f239fefc14226f655477179801c734749a04d4b4Aditya Kali#include "ext2fs/ext2fs.h" 16f239fefc14226f655477179801c734749a04d4b4Aditya Kali#include "e2p/e2p.h" 17f239fefc14226f655477179801c734749a04d4b4Aditya Kali 18f239fefc14226f655477179801c734749a04d4b4Aditya Kali#include "quotaio.h" 19f239fefc14226f655477179801c734749a04d4b4Aditya Kali#include "quotaio_v2.h" 20f239fefc14226f655477179801c734749a04d4b4Aditya Kali#include "quotaio_tree.h" 21f239fefc14226f655477179801c734749a04d4b4Aditya Kali#include "common.h" 223dca12fb62448f52663c859a089244d9cf37c5e3Theodore Ts'o#include "dict.h" 23f239fefc14226f655477179801c734749a04d4b4Aditya Kali 24f239fefc14226f655477179801c734749a04d4b4Aditya Kali/* Needed for architectures where sizeof(int) != sizeof(void *) */ 25f239fefc14226f655477179801c734749a04d4b4Aditya Kali#define UINT_TO_VOIDPTR(val) ((void *)(intptr_t)(val)) 26f239fefc14226f655477179801c734749a04d4b4Aditya Kali#define VOIDPTR_TO_UINT(ptr) ((unsigned int)(intptr_t)(ptr)) 27f239fefc14226f655477179801c734749a04d4b4Aditya Kali 2800eb0eee0addfd3b7ede98b85e00dff1547838a0Andreas Dilger#if DEBUG_QUOTA 29f239fefc14226f655477179801c734749a04d4b4Aditya Kalistatic void print_inode(struct ext2_inode *inode) 30f239fefc14226f655477179801c734749a04d4b4Aditya Kali{ 31f239fefc14226f655477179801c734749a04d4b4Aditya Kali if (!inode) 32f239fefc14226f655477179801c734749a04d4b4Aditya Kali return; 33f239fefc14226f655477179801c734749a04d4b4Aditya Kali 34f239fefc14226f655477179801c734749a04d4b4Aditya Kali fprintf(stderr, " i_mode = %d\n", inode->i_mode); 35f239fefc14226f655477179801c734749a04d4b4Aditya Kali fprintf(stderr, " i_uid = %d\n", inode->i_uid); 36f239fefc14226f655477179801c734749a04d4b4Aditya Kali fprintf(stderr, " i_size = %d\n", inode->i_size); 37f239fefc14226f655477179801c734749a04d4b4Aditya Kali fprintf(stderr, " i_atime = %d\n", inode->i_atime); 38f239fefc14226f655477179801c734749a04d4b4Aditya Kali fprintf(stderr, " i_ctime = %d\n", inode->i_ctime); 39f239fefc14226f655477179801c734749a04d4b4Aditya Kali fprintf(stderr, " i_mtime = %d\n", inode->i_mtime); 40f239fefc14226f655477179801c734749a04d4b4Aditya Kali fprintf(stderr, " i_dtime = %d\n", inode->i_dtime); 41f239fefc14226f655477179801c734749a04d4b4Aditya Kali fprintf(stderr, " i_gid = %d\n", inode->i_gid); 42f239fefc14226f655477179801c734749a04d4b4Aditya Kali fprintf(stderr, " i_links_count = %d\n", inode->i_links_count); 43f239fefc14226f655477179801c734749a04d4b4Aditya Kali fprintf(stderr, " i_blocks = %d\n", inode->i_blocks); 44f239fefc14226f655477179801c734749a04d4b4Aditya Kali fprintf(stderr, " i_flags = %d\n", inode->i_flags); 45f239fefc14226f655477179801c734749a04d4b4Aditya Kali 46f239fefc14226f655477179801c734749a04d4b4Aditya Kali return; 47f239fefc14226f655477179801c734749a04d4b4Aditya Kali} 48a0811c1a0ea18d4aebb4a16e7189501b80d4bc77Theodore Ts'o 49a0811c1a0ea18d4aebb4a16e7189501b80d4bc77Theodore Ts'ostatic void print_dquot(const char *desc, struct dquot *dq) 50a0811c1a0ea18d4aebb4a16e7189501b80d4bc77Theodore Ts'o{ 51a0811c1a0ea18d4aebb4a16e7189501b80d4bc77Theodore Ts'o if (desc) 52a0811c1a0ea18d4aebb4a16e7189501b80d4bc77Theodore Ts'o fprintf(stderr, "%s: ", desc); 53a0811c1a0ea18d4aebb4a16e7189501b80d4bc77Theodore Ts'o fprintf(stderr, "%u %lld:%lld:%lld %lld:%lld:%lld\n", 54a0811c1a0ea18d4aebb4a16e7189501b80d4bc77Theodore Ts'o dq->dq_id, dq->dq_dqb.dqb_curspace, 55a0811c1a0ea18d4aebb4a16e7189501b80d4bc77Theodore Ts'o dq->dq_dqb.dqb_bsoftlimit, dq->dq_dqb.dqb_bhardlimit, 56a0811c1a0ea18d4aebb4a16e7189501b80d4bc77Theodore Ts'o dq->dq_dqb.dqb_curinodes, 57a0811c1a0ea18d4aebb4a16e7189501b80d4bc77Theodore Ts'o dq->dq_dqb.dqb_isoftlimit, dq->dq_dqb.dqb_ihardlimit); 58a0811c1a0ea18d4aebb4a16e7189501b80d4bc77Theodore Ts'o} 59a0811c1a0ea18d4aebb4a16e7189501b80d4bc77Theodore Ts'o#else 6025f291c9b32d8017e6969c72a75e37d354c0570bTheodore Ts'ostatic void print_dquot(const char *desc EXT2FS_ATTR((unused)), 6125f291c9b32d8017e6969c72a75e37d354c0570bTheodore Ts'o struct dquot *dq EXT2FS_ATTR((unused))) 62a0811c1a0ea18d4aebb4a16e7189501b80d4bc77Theodore Ts'o{ 63a0811c1a0ea18d4aebb4a16e7189501b80d4bc77Theodore Ts'o} 6400eb0eee0addfd3b7ede98b85e00dff1547838a0Andreas Dilger#endif 65f239fefc14226f655477179801c734749a04d4b4Aditya Kali 66f239fefc14226f655477179801c734749a04d4b4Aditya Kali/* 67f239fefc14226f655477179801c734749a04d4b4Aditya Kali * Returns 0 if not able to find the quota file, otherwise returns its 68f239fefc14226f655477179801c734749a04d4b4Aditya Kali * inode number. 69f239fefc14226f655477179801c734749a04d4b4Aditya Kali */ 702d2d799c72610f4d9b4910e7f1516f11288e1cf1Li Xiint quota_file_exists(ext2_filsys fs, enum quota_type qtype) 71f239fefc14226f655477179801c734749a04d4b4Aditya Kali{ 72f239fefc14226f655477179801c734749a04d4b4Aditya Kali char qf_name[256]; 73f239fefc14226f655477179801c734749a04d4b4Aditya Kali errcode_t ret; 74f239fefc14226f655477179801c734749a04d4b4Aditya Kali ext2_ino_t ino; 75f239fefc14226f655477179801c734749a04d4b4Aditya Kali 7636e4e21f511423450285568ceb26b3ddb233e286Theodore Ts'o if (qtype >= MAXQUOTAS) 77f239fefc14226f655477179801c734749a04d4b4Aditya Kali return -EINVAL; 78f239fefc14226f655477179801c734749a04d4b4Aditya Kali 792ae58b6d5c73e044f3d498feea5d81892af2671fJan Kara quota_get_qf_name(qtype, QFMT_VFS_V1, qf_name); 80f239fefc14226f655477179801c734749a04d4b4Aditya Kali 81f239fefc14226f655477179801c734749a04d4b4Aditya Kali ret = ext2fs_lookup(fs, EXT2_ROOT_INO, qf_name, strlen(qf_name), 0, 82f239fefc14226f655477179801c734749a04d4b4Aditya Kali &ino); 83f239fefc14226f655477179801c734749a04d4b4Aditya Kali if (ret) 84f239fefc14226f655477179801c734749a04d4b4Aditya Kali return 0; 85f239fefc14226f655477179801c734749a04d4b4Aditya Kali 86f239fefc14226f655477179801c734749a04d4b4Aditya Kali return ino; 87f239fefc14226f655477179801c734749a04d4b4Aditya Kali} 88f239fefc14226f655477179801c734749a04d4b4Aditya Kali 89f239fefc14226f655477179801c734749a04d4b4Aditya Kali/* 90f239fefc14226f655477179801c734749a04d4b4Aditya Kali * Set the value for reserved quota inode number field in superblock. 91f239fefc14226f655477179801c734749a04d4b4Aditya Kali */ 922d2d799c72610f4d9b4910e7f1516f11288e1cf1Li Xivoid quota_set_sb_inum(ext2_filsys fs, ext2_ino_t ino, enum quota_type qtype) 93f239fefc14226f655477179801c734749a04d4b4Aditya Kali{ 94f239fefc14226f655477179801c734749a04d4b4Aditya Kali ext2_ino_t *inump; 95f239fefc14226f655477179801c734749a04d4b4Aditya Kali 962d2d799c72610f4d9b4910e7f1516f11288e1cf1Li Xi inump = quota_sb_inump(fs->super, qtype); 97f239fefc14226f655477179801c734749a04d4b4Aditya Kali 98f239fefc14226f655477179801c734749a04d4b4Aditya Kali log_debug("setting quota ino in superblock: ino=%u, type=%d", ino, 99f239fefc14226f655477179801c734749a04d4b4Aditya Kali qtype); 100f239fefc14226f655477179801c734749a04d4b4Aditya Kali *inump = ino; 101f239fefc14226f655477179801c734749a04d4b4Aditya Kali ext2fs_mark_super_dirty(fs); 102f239fefc14226f655477179801c734749a04d4b4Aditya Kali} 103f239fefc14226f655477179801c734749a04d4b4Aditya Kali 1042d2d799c72610f4d9b4910e7f1516f11288e1cf1Li Xierrcode_t quota_remove_inode(ext2_filsys fs, enum quota_type qtype) 105f239fefc14226f655477179801c734749a04d4b4Aditya Kali{ 106f239fefc14226f655477179801c734749a04d4b4Aditya Kali ext2_ino_t qf_ino; 107fa8b1c0281fa7384faf06b2f4c768dce1996bd6dTheodore Ts'o errcode_t retval; 108f239fefc14226f655477179801c734749a04d4b4Aditya Kali 109fa8b1c0281fa7384faf06b2f4c768dce1996bd6dTheodore Ts'o retval = ext2fs_read_bitmaps(fs); 110fa8b1c0281fa7384faf06b2f4c768dce1996bd6dTheodore Ts'o if (retval) { 111a701823a31505c5765d327d02bb14aa43fc34ae5Theodore Ts'o log_debug("Couldn't read bitmaps: %s", error_message(retval)); 112fa8b1c0281fa7384faf06b2f4c768dce1996bd6dTheodore Ts'o return retval; 113fa8b1c0281fa7384faf06b2f4c768dce1996bd6dTheodore Ts'o } 114a701823a31505c5765d327d02bb14aa43fc34ae5Theodore Ts'o 1152d2d799c72610f4d9b4910e7f1516f11288e1cf1Li Xi qf_ino = *quota_sb_inump(fs->super, qtype); 116a701823a31505c5765d327d02bb14aa43fc34ae5Theodore Ts'o if (qf_ino == 0) 117a701823a31505c5765d327d02bb14aa43fc34ae5Theodore Ts'o return 0; 118a701823a31505c5765d327d02bb14aa43fc34ae5Theodore Ts'o retval = quota_inode_truncate(fs, qf_ino); 119a701823a31505c5765d327d02bb14aa43fc34ae5Theodore Ts'o if (retval) 120a701823a31505c5765d327d02bb14aa43fc34ae5Theodore Ts'o return retval; 121a701823a31505c5765d327d02bb14aa43fc34ae5Theodore Ts'o if (qf_ino >= EXT2_FIRST_INODE(fs->super)) { 122080e09b46ff1f6b00b26231868002e781e98adf2Li Xi struct ext2_inode inode; 123080e09b46ff1f6b00b26231868002e781e98adf2Li Xi 124080e09b46ff1f6b00b26231868002e781e98adf2Li Xi retval = ext2fs_read_inode(fs, qf_ino, &inode); 125080e09b46ff1f6b00b26231868002e781e98adf2Li Xi if (!retval) { 126080e09b46ff1f6b00b26231868002e781e98adf2Li Xi memset(&inode, 0, sizeof(struct ext2_inode)); 127080e09b46ff1f6b00b26231868002e781e98adf2Li Xi ext2fs_write_inode(fs, qf_ino, &inode); 128080e09b46ff1f6b00b26231868002e781e98adf2Li Xi } 129080e09b46ff1f6b00b26231868002e781e98adf2Li Xi ext2fs_inode_alloc_stats2(fs, qf_ino, -1, 0); 130080e09b46ff1f6b00b26231868002e781e98adf2Li Xi ext2fs_mark_ib_dirty(fs); 131080e09b46ff1f6b00b26231868002e781e98adf2Li Xi 132080e09b46ff1f6b00b26231868002e781e98adf2Li Xi } 133080e09b46ff1f6b00b26231868002e781e98adf2Li Xi quota_set_sb_inum(fs, 0, qtype); 134f239fefc14226f655477179801c734749a04d4b4Aditya Kali 135f239fefc14226f655477179801c734749a04d4b4Aditya Kali ext2fs_mark_super_dirty(fs); 13643075b42bdff509cc567bd870a32072edf05d04cNiu Yawei fs->flags &= ~EXT2_FLAG_SUPER_ONLY; 137fa8b1c0281fa7384faf06b2f4c768dce1996bd6dTheodore Ts'o retval = ext2fs_write_bitmaps(fs); 138fa8b1c0281fa7384faf06b2f4c768dce1996bd6dTheodore Ts'o if (retval) { 139a701823a31505c5765d327d02bb14aa43fc34ae5Theodore Ts'o log_debug("Couldn't write bitmaps: %s", error_message(retval)); 140fa8b1c0281fa7384faf06b2f4c768dce1996bd6dTheodore Ts'o return retval; 141fa8b1c0281fa7384faf06b2f4c768dce1996bd6dTheodore Ts'o } 142f239fefc14226f655477179801c734749a04d4b4Aditya Kali return 0; 143f239fefc14226f655477179801c734749a04d4b4Aditya Kali} 144f239fefc14226f655477179801c734749a04d4b4Aditya Kali 145f239fefc14226f655477179801c734749a04d4b4Aditya Kalistatic void write_dquots(dict_t *dict, struct quota_handle *qh) 146f239fefc14226f655477179801c734749a04d4b4Aditya Kali{ 147f239fefc14226f655477179801c734749a04d4b4Aditya Kali dnode_t *n; 148f239fefc14226f655477179801c734749a04d4b4Aditya Kali struct dquot *dq; 149f239fefc14226f655477179801c734749a04d4b4Aditya Kali 150f239fefc14226f655477179801c734749a04d4b4Aditya Kali for (n = dict_first(dict); n; n = dict_next(dict, n)) { 151f239fefc14226f655477179801c734749a04d4b4Aditya Kali dq = dnode_get(n); 152f239fefc14226f655477179801c734749a04d4b4Aditya Kali if (dq) { 153a0811c1a0ea18d4aebb4a16e7189501b80d4bc77Theodore Ts'o print_dquot("write", dq); 154f239fefc14226f655477179801c734749a04d4b4Aditya Kali dq->dq_h = qh; 155f239fefc14226f655477179801c734749a04d4b4Aditya Kali update_grace_times(dq); 156b5ba6f5b9da9d4e3d6f52ef9470ec12a161b1a7fTheodore Ts'o qh->qh_ops->commit_dquot(dq); 157f239fefc14226f655477179801c734749a04d4b4Aditya Kali } 158f239fefc14226f655477179801c734749a04d4b4Aditya Kali } 159f239fefc14226f655477179801c734749a04d4b4Aditya Kali} 160f239fefc14226f655477179801c734749a04d4b4Aditya Kali 1612d2d799c72610f4d9b4910e7f1516f11288e1cf1Li Xierrcode_t quota_write_inode(quota_ctx_t qctx, unsigned int qtype_bits) 162f239fefc14226f655477179801c734749a04d4b4Aditya Kali{ 1632d2d799c72610f4d9b4910e7f1516f11288e1cf1Li Xi int retval = 0; 1642d2d799c72610f4d9b4910e7f1516f11288e1cf1Li Xi enum quota_type qtype; 165f239fefc14226f655477179801c734749a04d4b4Aditya Kali dict_t *dict; 166f239fefc14226f655477179801c734749a04d4b4Aditya Kali ext2_filsys fs; 16700eb0eee0addfd3b7ede98b85e00dff1547838a0Andreas Dilger struct quota_handle *h = NULL; 168f239fefc14226f655477179801c734749a04d4b4Aditya Kali int fmt = QFMT_VFS_V1; 169f239fefc14226f655477179801c734749a04d4b4Aditya Kali 170f239fefc14226f655477179801c734749a04d4b4Aditya Kali if (!qctx) 171edbfd75d8fb4a13eccc2cadb12a453c3425d17d1Theodore Ts'o return 0; 172f239fefc14226f655477179801c734749a04d4b4Aditya Kali 173f239fefc14226f655477179801c734749a04d4b4Aditya Kali fs = qctx->fs; 174a86d55da8bf41335aa2fc5ec16ca63859d918e81Aditya Kali retval = ext2fs_get_mem(sizeof(struct quota_handle), &h); 175a86d55da8bf41335aa2fc5ec16ca63859d918e81Aditya Kali if (retval) { 176a701823a31505c5765d327d02bb14aa43fc34ae5Theodore Ts'o log_debug("Unable to allocate quota handle: %s", 1773f10707d90801ec84148b7f8ec6ad9c8470853eeTheodore Ts'o error_message(retval)); 178a86d55da8bf41335aa2fc5ec16ca63859d918e81Aditya Kali goto out; 179a86d55da8bf41335aa2fc5ec16ca63859d918e81Aditya Kali } 180a86d55da8bf41335aa2fc5ec16ca63859d918e81Aditya Kali 1813f10707d90801ec84148b7f8ec6ad9c8470853eeTheodore Ts'o retval = ext2fs_read_bitmaps(fs); 1823f10707d90801ec84148b7f8ec6ad9c8470853eeTheodore Ts'o if (retval) { 183a701823a31505c5765d327d02bb14aa43fc34ae5Theodore Ts'o log_debug("Couldn't read bitmaps: %s", error_message(retval)); 1843f10707d90801ec84148b7f8ec6ad9c8470853eeTheodore Ts'o goto out; 1853f10707d90801ec84148b7f8ec6ad9c8470853eeTheodore Ts'o } 186f239fefc14226f655477179801c734749a04d4b4Aditya Kali 1872d2d799c72610f4d9b4910e7f1516f11288e1cf1Li Xi for (qtype = 0; qtype < MAXQUOTAS; qtype++) { 1882d2d799c72610f4d9b4910e7f1516f11288e1cf1Li Xi if (((1 << qtype) & qtype_bits) == 0) 189f239fefc14226f655477179801c734749a04d4b4Aditya Kali continue; 190f239fefc14226f655477179801c734749a04d4b4Aditya Kali 1912d2d799c72610f4d9b4910e7f1516f11288e1cf1Li Xi dict = qctx->quota_dict[qtype]; 192f239fefc14226f655477179801c734749a04d4b4Aditya Kali if (!dict) 193f239fefc14226f655477179801c734749a04d4b4Aditya Kali continue; 194f239fefc14226f655477179801c734749a04d4b4Aditya Kali 1952d2d799c72610f4d9b4910e7f1516f11288e1cf1Li Xi retval = quota_file_create(h, fs, qtype, fmt); 196f239fefc14226f655477179801c734749a04d4b4Aditya Kali if (retval < 0) { 197a701823a31505c5765d327d02bb14aa43fc34ae5Theodore Ts'o log_debug("Cannot initialize io on quotafile"); 198f239fefc14226f655477179801c734749a04d4b4Aditya Kali continue; 199f239fefc14226f655477179801c734749a04d4b4Aditya Kali } 200f239fefc14226f655477179801c734749a04d4b4Aditya Kali 201f239fefc14226f655477179801c734749a04d4b4Aditya Kali write_dquots(dict, h); 202cbc1280dc73bce297b9d7f7ff9b8a17f709ef2b1Theodore Ts'o retval = quota_file_close(qctx, h); 203f239fefc14226f655477179801c734749a04d4b4Aditya Kali if (retval < 0) { 204f239fefc14226f655477179801c734749a04d4b4Aditya Kali log_err("Cannot finish IO on new quotafile: %s", 205f239fefc14226f655477179801c734749a04d4b4Aditya Kali strerror(errno)); 206f239fefc14226f655477179801c734749a04d4b4Aditya Kali if (h->qh_qf.e2_file) 207f239fefc14226f655477179801c734749a04d4b4Aditya Kali ext2fs_file_close(h->qh_qf.e2_file); 208a701823a31505c5765d327d02bb14aa43fc34ae5Theodore Ts'o (void) quota_inode_truncate(fs, h->qh_qf.ino); 209f239fefc14226f655477179801c734749a04d4b4Aditya Kali continue; 210f239fefc14226f655477179801c734749a04d4b4Aditya Kali } 211f239fefc14226f655477179801c734749a04d4b4Aditya Kali 212f239fefc14226f655477179801c734749a04d4b4Aditya Kali /* Set quota inode numbers in superblock. */ 2132d2d799c72610f4d9b4910e7f1516f11288e1cf1Li Xi quota_set_sb_inum(fs, h->qh_qf.ino, qtype); 214f239fefc14226f655477179801c734749a04d4b4Aditya Kali ext2fs_mark_super_dirty(fs); 215f239fefc14226f655477179801c734749a04d4b4Aditya Kali ext2fs_mark_bb_dirty(fs); 216f239fefc14226f655477179801c734749a04d4b4Aditya Kali fs->flags &= ~EXT2_FLAG_SUPER_ONLY; 217f239fefc14226f655477179801c734749a04d4b4Aditya Kali } 218f239fefc14226f655477179801c734749a04d4b4Aditya Kali 2193f10707d90801ec84148b7f8ec6ad9c8470853eeTheodore Ts'o retval = ext2fs_write_bitmaps(fs); 2203f10707d90801ec84148b7f8ec6ad9c8470853eeTheodore Ts'o if (retval) { 221a701823a31505c5765d327d02bb14aa43fc34ae5Theodore Ts'o log_debug("Couldn't write bitmaps: %s", error_message(retval)); 2223f10707d90801ec84148b7f8ec6ad9c8470853eeTheodore Ts'o goto out; 2233f10707d90801ec84148b7f8ec6ad9c8470853eeTheodore Ts'o } 224a86d55da8bf41335aa2fc5ec16ca63859d918e81Aditya Kaliout: 225a86d55da8bf41335aa2fc5ec16ca63859d918e81Aditya Kali if (h) 226a86d55da8bf41335aa2fc5ec16ca63859d918e81Aditya Kali ext2fs_free_mem(&h); 227f239fefc14226f655477179801c734749a04d4b4Aditya Kali return retval; 228f239fefc14226f655477179801c734749a04d4b4Aditya Kali} 229f239fefc14226f655477179801c734749a04d4b4Aditya Kali 230f239fefc14226f655477179801c734749a04d4b4Aditya Kali/******************************************************************/ 231f239fefc14226f655477179801c734749a04d4b4Aditya Kali/* Helper functions for computing quota in memory. */ 232f239fefc14226f655477179801c734749a04d4b4Aditya Kali/******************************************************************/ 233f239fefc14226f655477179801c734749a04d4b4Aditya Kali 234f239fefc14226f655477179801c734749a04d4b4Aditya Kalistatic int dict_uint_cmp(const void *a, const void *b) 235f239fefc14226f655477179801c734749a04d4b4Aditya Kali{ 236f239fefc14226f655477179801c734749a04d4b4Aditya Kali unsigned int c, d; 237f239fefc14226f655477179801c734749a04d4b4Aditya Kali 238f239fefc14226f655477179801c734749a04d4b4Aditya Kali c = VOIDPTR_TO_UINT(a); 239f239fefc14226f655477179801c734749a04d4b4Aditya Kali d = VOIDPTR_TO_UINT(b); 240f239fefc14226f655477179801c734749a04d4b4Aditya Kali 2414cf0b0fe443566940098308c2a9eb28fdb000166Niu Yawei if (c == d) 2424cf0b0fe443566940098308c2a9eb28fdb000166Niu Yawei return 0; 2434cf0b0fe443566940098308c2a9eb28fdb000166Niu Yawei else if (c > d) 2444cf0b0fe443566940098308c2a9eb28fdb000166Niu Yawei return 1; 2454cf0b0fe443566940098308c2a9eb28fdb000166Niu Yawei else 2464cf0b0fe443566940098308c2a9eb28fdb000166Niu Yawei return -1; 247f239fefc14226f655477179801c734749a04d4b4Aditya Kali} 248f239fefc14226f655477179801c734749a04d4b4Aditya Kali 249bc1ec4b4593d0c89dc52b9042297b3aeb65e08cdTheodore Ts'ostatic inline qid_t get_qid(struct ext2_inode_large *inode, enum quota_type qtype) 250f239fefc14226f655477179801c734749a04d4b4Aditya Kali{ 251a701823a31505c5765d327d02bb14aa43fc34ae5Theodore Ts'o unsigned int inode_size; 252080e09b46ff1f6b00b26231868002e781e98adf2Li Xi 2532d2d799c72610f4d9b4910e7f1516f11288e1cf1Li Xi switch (qtype) { 2542d2d799c72610f4d9b4910e7f1516f11288e1cf1Li Xi case USRQUOTA: 255f239fefc14226f655477179801c734749a04d4b4Aditya Kali return inode_uid(*inode); 2562d2d799c72610f4d9b4910e7f1516f11288e1cf1Li Xi case GRPQUOTA: 2572d2d799c72610f4d9b4910e7f1516f11288e1cf1Li Xi return inode_gid(*inode); 258080e09b46ff1f6b00b26231868002e781e98adf2Li Xi case PRJQUOTA: 259080e09b46ff1f6b00b26231868002e781e98adf2Li Xi inode_size = EXT2_GOOD_OLD_INODE_SIZE + 260bc1ec4b4593d0c89dc52b9042297b3aeb65e08cdTheodore Ts'o inode->i_extra_isize; 261080e09b46ff1f6b00b26231868002e781e98adf2Li Xi if (inode_includes(inode_size, i_projid)) 262bc1ec4b4593d0c89dc52b9042297b3aeb65e08cdTheodore Ts'o return inode_projid(*inode); 2632d2d799c72610f4d9b4910e7f1516f11288e1cf1Li Xi default: 2642d2d799c72610f4d9b4910e7f1516f11288e1cf1Li Xi return 0; 2652d2d799c72610f4d9b4910e7f1516f11288e1cf1Li Xi } 2662d2d799c72610f4d9b4910e7f1516f11288e1cf1Li Xi 2672d2d799c72610f4d9b4910e7f1516f11288e1cf1Li Xi return 0; 268f239fefc14226f655477179801c734749a04d4b4Aditya Kali} 269f239fefc14226f655477179801c734749a04d4b4Aditya Kali 270f239fefc14226f655477179801c734749a04d4b4Aditya Kalistatic void quota_dnode_free(dnode_t *node, 271f239fefc14226f655477179801c734749a04d4b4Aditya Kali void *context EXT2FS_ATTR((unused))) 272f239fefc14226f655477179801c734749a04d4b4Aditya Kali{ 273f239fefc14226f655477179801c734749a04d4b4Aditya Kali void *ptr = node ? dnode_get(node) : 0; 274f239fefc14226f655477179801c734749a04d4b4Aditya Kali 275a86d55da8bf41335aa2fc5ec16ca63859d918e81Aditya Kali ext2fs_free_mem(&ptr); 276f239fefc14226f655477179801c734749a04d4b4Aditya Kali free(node); 277f239fefc14226f655477179801c734749a04d4b4Aditya Kali} 278f239fefc14226f655477179801c734749a04d4b4Aditya Kali 279f239fefc14226f655477179801c734749a04d4b4Aditya Kali/* 280a86d55da8bf41335aa2fc5ec16ca63859d918e81Aditya Kali * Set up the quota tracking data structures. 281f239fefc14226f655477179801c734749a04d4b4Aditya Kali */ 2822d2d799c72610f4d9b4910e7f1516f11288e1cf1Li Xierrcode_t quota_init_context(quota_ctx_t *qctx, ext2_filsys fs, 2832d2d799c72610f4d9b4910e7f1516f11288e1cf1Li Xi unsigned int qtype_bits) 284f239fefc14226f655477179801c734749a04d4b4Aditya Kali{ 285cbc1280dc73bce297b9d7f7ff9b8a17f709ef2b1Theodore Ts'o errcode_t err; 286f239fefc14226f655477179801c734749a04d4b4Aditya Kali dict_t *dict; 287f239fefc14226f655477179801c734749a04d4b4Aditya Kali quota_ctx_t ctx; 2882d2d799c72610f4d9b4910e7f1516f11288e1cf1Li Xi enum quota_type qtype; 289f239fefc14226f655477179801c734749a04d4b4Aditya Kali 290a86d55da8bf41335aa2fc5ec16ca63859d918e81Aditya Kali err = ext2fs_get_mem(sizeof(struct quota_ctx), &ctx); 291a86d55da8bf41335aa2fc5ec16ca63859d918e81Aditya Kali if (err) { 292a701823a31505c5765d327d02bb14aa43fc34ae5Theodore Ts'o log_debug("Failed to allocate quota context"); 293a86d55da8bf41335aa2fc5ec16ca63859d918e81Aditya Kali return err; 294a86d55da8bf41335aa2fc5ec16ca63859d918e81Aditya Kali } 295a86d55da8bf41335aa2fc5ec16ca63859d918e81Aditya Kali 296f239fefc14226f655477179801c734749a04d4b4Aditya Kali memset(ctx, 0, sizeof(struct quota_ctx)); 2972d2d799c72610f4d9b4910e7f1516f11288e1cf1Li Xi for (qtype = 0; qtype < MAXQUOTAS; qtype++) { 2982d2d799c72610f4d9b4910e7f1516f11288e1cf1Li Xi ctx->quota_file[qtype] = NULL; 2992d2d799c72610f4d9b4910e7f1516f11288e1cf1Li Xi if (((1 << qtype) & qtype_bits) == 0) 300f239fefc14226f655477179801c734749a04d4b4Aditya Kali continue; 301a86d55da8bf41335aa2fc5ec16ca63859d918e81Aditya Kali err = ext2fs_get_mem(sizeof(dict_t), &dict); 302a86d55da8bf41335aa2fc5ec16ca63859d918e81Aditya Kali if (err) { 303a701823a31505c5765d327d02bb14aa43fc34ae5Theodore Ts'o log_debug("Failed to allocate dictionary"); 304b2778bcb8c37705ea97fee58199446d83dbda927Darrick J. Wong quota_release_context(&ctx); 305a86d55da8bf41335aa2fc5ec16ca63859d918e81Aditya Kali return err; 306a86d55da8bf41335aa2fc5ec16ca63859d918e81Aditya Kali } 3072d2d799c72610f4d9b4910e7f1516f11288e1cf1Li Xi ctx->quota_dict[qtype] = dict; 308f239fefc14226f655477179801c734749a04d4b4Aditya Kali dict_init(dict, DICTCOUNT_T_MAX, dict_uint_cmp); 309f239fefc14226f655477179801c734749a04d4b4Aditya Kali dict_set_allocator(dict, NULL, quota_dnode_free, NULL); 310f239fefc14226f655477179801c734749a04d4b4Aditya Kali } 311f239fefc14226f655477179801c734749a04d4b4Aditya Kali 312f239fefc14226f655477179801c734749a04d4b4Aditya Kali ctx->fs = fs; 313f239fefc14226f655477179801c734749a04d4b4Aditya Kali *qctx = ctx; 314a86d55da8bf41335aa2fc5ec16ca63859d918e81Aditya Kali return 0; 315f239fefc14226f655477179801c734749a04d4b4Aditya Kali} 316f239fefc14226f655477179801c734749a04d4b4Aditya Kali 317a86d55da8bf41335aa2fc5ec16ca63859d918e81Aditya Kalivoid quota_release_context(quota_ctx_t *qctx) 318f239fefc14226f655477179801c734749a04d4b4Aditya Kali{ 319cbc1280dc73bce297b9d7f7ff9b8a17f709ef2b1Theodore Ts'o errcode_t err; 320f239fefc14226f655477179801c734749a04d4b4Aditya Kali dict_t *dict; 3212d2d799c72610f4d9b4910e7f1516f11288e1cf1Li Xi enum quota_type qtype; 322f239fefc14226f655477179801c734749a04d4b4Aditya Kali quota_ctx_t ctx; 323f239fefc14226f655477179801c734749a04d4b4Aditya Kali 324f239fefc14226f655477179801c734749a04d4b4Aditya Kali if (!qctx) 325f239fefc14226f655477179801c734749a04d4b4Aditya Kali return; 326f239fefc14226f655477179801c734749a04d4b4Aditya Kali 327f239fefc14226f655477179801c734749a04d4b4Aditya Kali ctx = *qctx; 3282d2d799c72610f4d9b4910e7f1516f11288e1cf1Li Xi for (qtype = 0; qtype < MAXQUOTAS; qtype++) { 3292d2d799c72610f4d9b4910e7f1516f11288e1cf1Li Xi dict = ctx->quota_dict[qtype]; 3302d2d799c72610f4d9b4910e7f1516f11288e1cf1Li Xi ctx->quota_dict[qtype] = 0; 331f239fefc14226f655477179801c734749a04d4b4Aditya Kali if (dict) { 332f239fefc14226f655477179801c734749a04d4b4Aditya Kali dict_free_nodes(dict); 333f239fefc14226f655477179801c734749a04d4b4Aditya Kali free(dict); 334f239fefc14226f655477179801c734749a04d4b4Aditya Kali } 3352d2d799c72610f4d9b4910e7f1516f11288e1cf1Li Xi if (ctx->quota_file[qtype]) { 3362d2d799c72610f4d9b4910e7f1516f11288e1cf1Li Xi err = quota_file_close(ctx, ctx->quota_file[qtype]); 337cbc1280dc73bce297b9d7f7ff9b8a17f709ef2b1Theodore Ts'o if (err) { 338cbc1280dc73bce297b9d7f7ff9b8a17f709ef2b1Theodore Ts'o log_err("Cannot close quotafile: %s", 339cbc1280dc73bce297b9d7f7ff9b8a17f709ef2b1Theodore Ts'o strerror(errno)); 3402d2d799c72610f4d9b4910e7f1516f11288e1cf1Li Xi ext2fs_free_mem(&ctx->quota_file[qtype]); 341cbc1280dc73bce297b9d7f7ff9b8a17f709ef2b1Theodore Ts'o } 342cbc1280dc73bce297b9d7f7ff9b8a17f709ef2b1Theodore Ts'o } 343f239fefc14226f655477179801c734749a04d4b4Aditya Kali } 344f239fefc14226f655477179801c734749a04d4b4Aditya Kali *qctx = NULL; 345f239fefc14226f655477179801c734749a04d4b4Aditya Kali free(ctx); 346f239fefc14226f655477179801c734749a04d4b4Aditya Kali} 347f239fefc14226f655477179801c734749a04d4b4Aditya Kali 348f239fefc14226f655477179801c734749a04d4b4Aditya Kalistatic struct dquot *get_dq(dict_t *dict, __u32 key) 349f239fefc14226f655477179801c734749a04d4b4Aditya Kali{ 350f239fefc14226f655477179801c734749a04d4b4Aditya Kali struct dquot *dq; 351f239fefc14226f655477179801c734749a04d4b4Aditya Kali dnode_t *n; 352f239fefc14226f655477179801c734749a04d4b4Aditya Kali 353f239fefc14226f655477179801c734749a04d4b4Aditya Kali n = dict_lookup(dict, UINT_TO_VOIDPTR(key)); 354f239fefc14226f655477179801c734749a04d4b4Aditya Kali if (n) 355f239fefc14226f655477179801c734749a04d4b4Aditya Kali dq = dnode_get(n); 356f239fefc14226f655477179801c734749a04d4b4Aditya Kali else { 357a86d55da8bf41335aa2fc5ec16ca63859d918e81Aditya Kali if (ext2fs_get_mem(sizeof(struct dquot), &dq)) { 3580ce0172984c807d3366e8db6e2a2b6ecae314832Andreas Dilger log_err("Unable to allocate dquot"); 359a86d55da8bf41335aa2fc5ec16ca63859d918e81Aditya Kali return NULL; 360a86d55da8bf41335aa2fc5ec16ca63859d918e81Aditya Kali } 361f239fefc14226f655477179801c734749a04d4b4Aditya Kali memset(dq, 0, sizeof(struct dquot)); 362f239fefc14226f655477179801c734749a04d4b4Aditya Kali dict_alloc_insert(dict, UINT_TO_VOIDPTR(key), dq); 3631527d99d378a4a45f1e36b197bed628ce28d73eeNiu Yawei dq->dq_id = key; 364f239fefc14226f655477179801c734749a04d4b4Aditya Kali } 365f239fefc14226f655477179801c734749a04d4b4Aditya Kali return dq; 366f239fefc14226f655477179801c734749a04d4b4Aditya Kali} 367f239fefc14226f655477179801c734749a04d4b4Aditya Kali 368f239fefc14226f655477179801c734749a04d4b4Aditya Kali 369f239fefc14226f655477179801c734749a04d4b4Aditya Kali/* 370f239fefc14226f655477179801c734749a04d4b4Aditya Kali * Called to update the blocks used by a particular inode 371f239fefc14226f655477179801c734749a04d4b4Aditya Kali */ 372bc1ec4b4593d0c89dc52b9042297b3aeb65e08cdTheodore Ts'ovoid quota_data_add(quota_ctx_t qctx, struct ext2_inode_large *inode, 37325f291c9b32d8017e6969c72a75e37d354c0570bTheodore Ts'o ext2_ino_t ino EXT2FS_ATTR((unused)), 374f239fefc14226f655477179801c734749a04d4b4Aditya Kali qsize_t space) 375f239fefc14226f655477179801c734749a04d4b4Aditya Kali{ 376f239fefc14226f655477179801c734749a04d4b4Aditya Kali struct dquot *dq; 377f239fefc14226f655477179801c734749a04d4b4Aditya Kali dict_t *dict; 3782d2d799c72610f4d9b4910e7f1516f11288e1cf1Li Xi enum quota_type qtype; 379f239fefc14226f655477179801c734749a04d4b4Aditya Kali 380f239fefc14226f655477179801c734749a04d4b4Aditya Kali if (!qctx) 381f239fefc14226f655477179801c734749a04d4b4Aditya Kali return; 382f239fefc14226f655477179801c734749a04d4b4Aditya Kali 383f239fefc14226f655477179801c734749a04d4b4Aditya Kali log_debug("ADD_DATA: Inode: %u, UID/GID: %u/%u, space: %ld", ino, 384f239fefc14226f655477179801c734749a04d4b4Aditya Kali inode_uid(*inode), 385f239fefc14226f655477179801c734749a04d4b4Aditya Kali inode_gid(*inode), space); 3862d2d799c72610f4d9b4910e7f1516f11288e1cf1Li Xi for (qtype = 0; qtype < MAXQUOTAS; qtype++) { 3872d2d799c72610f4d9b4910e7f1516f11288e1cf1Li Xi dict = qctx->quota_dict[qtype]; 388f239fefc14226f655477179801c734749a04d4b4Aditya Kali if (dict) { 3892d2d799c72610f4d9b4910e7f1516f11288e1cf1Li Xi dq = get_dq(dict, get_qid(inode, qtype)); 390a86d55da8bf41335aa2fc5ec16ca63859d918e81Aditya Kali if (dq) 391a86d55da8bf41335aa2fc5ec16ca63859d918e81Aditya Kali dq->dq_dqb.dqb_curspace += space; 392f239fefc14226f655477179801c734749a04d4b4Aditya Kali } 393f239fefc14226f655477179801c734749a04d4b4Aditya Kali } 394f239fefc14226f655477179801c734749a04d4b4Aditya Kali} 395f239fefc14226f655477179801c734749a04d4b4Aditya Kali 396f239fefc14226f655477179801c734749a04d4b4Aditya Kali/* 397f239fefc14226f655477179801c734749a04d4b4Aditya Kali * Called to remove some blocks used by a particular inode 398f239fefc14226f655477179801c734749a04d4b4Aditya Kali */ 399bc1ec4b4593d0c89dc52b9042297b3aeb65e08cdTheodore Ts'ovoid quota_data_sub(quota_ctx_t qctx, struct ext2_inode_large *inode, 40025f291c9b32d8017e6969c72a75e37d354c0570bTheodore Ts'o ext2_ino_t ino EXT2FS_ATTR((unused)), 401f239fefc14226f655477179801c734749a04d4b4Aditya Kali qsize_t space) 402f239fefc14226f655477179801c734749a04d4b4Aditya Kali{ 403f239fefc14226f655477179801c734749a04d4b4Aditya Kali struct dquot *dq; 404f239fefc14226f655477179801c734749a04d4b4Aditya Kali dict_t *dict; 4052d2d799c72610f4d9b4910e7f1516f11288e1cf1Li Xi enum quota_type qtype; 406f239fefc14226f655477179801c734749a04d4b4Aditya Kali 407f239fefc14226f655477179801c734749a04d4b4Aditya Kali if (!qctx) 408f239fefc14226f655477179801c734749a04d4b4Aditya Kali return; 409f239fefc14226f655477179801c734749a04d4b4Aditya Kali 410f239fefc14226f655477179801c734749a04d4b4Aditya Kali log_debug("SUB_DATA: Inode: %u, UID/GID: %u/%u, space: %ld", ino, 411f239fefc14226f655477179801c734749a04d4b4Aditya Kali inode_uid(*inode), 412f239fefc14226f655477179801c734749a04d4b4Aditya Kali inode_gid(*inode), space); 4132d2d799c72610f4d9b4910e7f1516f11288e1cf1Li Xi for (qtype = 0; qtype < MAXQUOTAS; qtype++) { 4142d2d799c72610f4d9b4910e7f1516f11288e1cf1Li Xi dict = qctx->quota_dict[qtype]; 415f239fefc14226f655477179801c734749a04d4b4Aditya Kali if (dict) { 4162d2d799c72610f4d9b4910e7f1516f11288e1cf1Li Xi dq = get_dq(dict, get_qid(inode, qtype)); 417f239fefc14226f655477179801c734749a04d4b4Aditya Kali dq->dq_dqb.dqb_curspace -= space; 418f239fefc14226f655477179801c734749a04d4b4Aditya Kali } 419f239fefc14226f655477179801c734749a04d4b4Aditya Kali } 420f239fefc14226f655477179801c734749a04d4b4Aditya Kali} 421f239fefc14226f655477179801c734749a04d4b4Aditya Kali 422f239fefc14226f655477179801c734749a04d4b4Aditya Kali/* 423f239fefc14226f655477179801c734749a04d4b4Aditya Kali * Called to count the files used by an inode's user/group 424f239fefc14226f655477179801c734749a04d4b4Aditya Kali */ 425bc1ec4b4593d0c89dc52b9042297b3aeb65e08cdTheodore Ts'ovoid quota_data_inodes(quota_ctx_t qctx, struct ext2_inode_large *inode, 42625f291c9b32d8017e6969c72a75e37d354c0570bTheodore Ts'o ext2_ino_t ino EXT2FS_ATTR((unused)), int adjust) 427f239fefc14226f655477179801c734749a04d4b4Aditya Kali{ 428f239fefc14226f655477179801c734749a04d4b4Aditya Kali struct dquot *dq; 429f239fefc14226f655477179801c734749a04d4b4Aditya Kali dict_t *dict; 4302d2d799c72610f4d9b4910e7f1516f11288e1cf1Li Xi enum quota_type qtype; 431f239fefc14226f655477179801c734749a04d4b4Aditya Kali 432f239fefc14226f655477179801c734749a04d4b4Aditya Kali if (!qctx) 433f239fefc14226f655477179801c734749a04d4b4Aditya Kali return; 434f239fefc14226f655477179801c734749a04d4b4Aditya Kali 435f239fefc14226f655477179801c734749a04d4b4Aditya Kali log_debug("ADJ_INODE: Inode: %u, UID/GID: %u/%u, adjust: %d", ino, 436f239fefc14226f655477179801c734749a04d4b4Aditya Kali inode_uid(*inode), 437f239fefc14226f655477179801c734749a04d4b4Aditya Kali inode_gid(*inode), adjust); 4382d2d799c72610f4d9b4910e7f1516f11288e1cf1Li Xi for (qtype = 0; qtype < MAXQUOTAS; qtype++) { 4392d2d799c72610f4d9b4910e7f1516f11288e1cf1Li Xi dict = qctx->quota_dict[qtype]; 440f239fefc14226f655477179801c734749a04d4b4Aditya Kali if (dict) { 4412d2d799c72610f4d9b4910e7f1516f11288e1cf1Li Xi dq = get_dq(dict, get_qid(inode, qtype)); 442f239fefc14226f655477179801c734749a04d4b4Aditya Kali dq->dq_dqb.dqb_curinodes += adjust; 443f239fefc14226f655477179801c734749a04d4b4Aditya Kali } 444f239fefc14226f655477179801c734749a04d4b4Aditya Kali } 445f239fefc14226f655477179801c734749a04d4b4Aditya Kali} 446f239fefc14226f655477179801c734749a04d4b4Aditya Kali 447a86d55da8bf41335aa2fc5ec16ca63859d918e81Aditya Kalierrcode_t quota_compute_usage(quota_ctx_t qctx) 448f239fefc14226f655477179801c734749a04d4b4Aditya Kali{ 449f239fefc14226f655477179801c734749a04d4b4Aditya Kali ext2_filsys fs; 450f239fefc14226f655477179801c734749a04d4b4Aditya Kali ext2_ino_t ino; 451f239fefc14226f655477179801c734749a04d4b4Aditya Kali errcode_t ret; 452bc1ec4b4593d0c89dc52b9042297b3aeb65e08cdTheodore Ts'o struct ext2_inode_large *inode; 4534bfb35e1e6489ccf92144d9977e4d0f8f14ac3b4Theodore Ts'o int inode_size; 454f239fefc14226f655477179801c734749a04d4b4Aditya Kali qsize_t space; 455f239fefc14226f655477179801c734749a04d4b4Aditya Kali ext2_inode_scan scan; 456f239fefc14226f655477179801c734749a04d4b4Aditya Kali 457f239fefc14226f655477179801c734749a04d4b4Aditya Kali if (!qctx) 458edbfd75d8fb4a13eccc2cadb12a453c3425d17d1Theodore Ts'o return 0; 459f239fefc14226f655477179801c734749a04d4b4Aditya Kali 460f239fefc14226f655477179801c734749a04d4b4Aditya Kali fs = qctx->fs; 461f239fefc14226f655477179801c734749a04d4b4Aditya Kali ret = ext2fs_open_inode_scan(fs, 0, &scan); 462f239fefc14226f655477179801c734749a04d4b4Aditya Kali if (ret) { 463f239fefc14226f655477179801c734749a04d4b4Aditya Kali log_err("while opening inode scan. ret=%ld", ret); 464f239fefc14226f655477179801c734749a04d4b4Aditya Kali return ret; 465f239fefc14226f655477179801c734749a04d4b4Aditya Kali } 4664bfb35e1e6489ccf92144d9977e4d0f8f14ac3b4Theodore Ts'o inode_size = fs->super->s_inode_size; 4674bfb35e1e6489ccf92144d9977e4d0f8f14ac3b4Theodore Ts'o inode = malloc(inode_size); 4684bfb35e1e6489ccf92144d9977e4d0f8f14ac3b4Theodore Ts'o if (!inode) 4694bfb35e1e6489ccf92144d9977e4d0f8f14ac3b4Theodore Ts'o return ENOMEM; 470f239fefc14226f655477179801c734749a04d4b4Aditya Kali while (1) { 471bc1ec4b4593d0c89dc52b9042297b3aeb65e08cdTheodore Ts'o ret = ext2fs_get_next_inode_full(scan, &ino, 472bc1ec4b4593d0c89dc52b9042297b3aeb65e08cdTheodore Ts'o EXT2_INODE(inode), inode_size); 473f239fefc14226f655477179801c734749a04d4b4Aditya Kali if (ret) { 474f239fefc14226f655477179801c734749a04d4b4Aditya Kali log_err("while getting next inode. ret=%ld", ret); 475f239fefc14226f655477179801c734749a04d4b4Aditya Kali ext2fs_close_inode_scan(scan); 4764bfb35e1e6489ccf92144d9977e4d0f8f14ac3b4Theodore Ts'o free(inode); 477f239fefc14226f655477179801c734749a04d4b4Aditya Kali return ret; 478f239fefc14226f655477179801c734749a04d4b4Aditya Kali } 479f239fefc14226f655477179801c734749a04d4b4Aditya Kali if (ino == 0) 480f239fefc14226f655477179801c734749a04d4b4Aditya Kali break; 4814bfb35e1e6489ccf92144d9977e4d0f8f14ac3b4Theodore Ts'o if (inode->i_links_count && 4825027751530980c61e313d265b1367fee90589cf4Aditya Kali (ino == EXT2_ROOT_INO || 4835027751530980c61e313d265b1367fee90589cf4Aditya Kali ino >= EXT2_FIRST_INODE(fs->super))) { 484bc1ec4b4593d0c89dc52b9042297b3aeb65e08cdTheodore Ts'o space = ext2fs_inode_i_blocks(fs, 485bc1ec4b4593d0c89dc52b9042297b3aeb65e08cdTheodore Ts'o EXT2_INODE(inode)) << 9; 4864bfb35e1e6489ccf92144d9977e4d0f8f14ac3b4Theodore Ts'o quota_data_add(qctx, inode, ino, space); 4874bfb35e1e6489ccf92144d9977e4d0f8f14ac3b4Theodore Ts'o quota_data_inodes(qctx, inode, ino, +1); 488f239fefc14226f655477179801c734749a04d4b4Aditya Kali } 489f239fefc14226f655477179801c734749a04d4b4Aditya Kali } 490f239fefc14226f655477179801c734749a04d4b4Aditya Kali 491f239fefc14226f655477179801c734749a04d4b4Aditya Kali ext2fs_close_inode_scan(scan); 4924bfb35e1e6489ccf92144d9977e4d0f8f14ac3b4Theodore Ts'o free(inode); 493f239fefc14226f655477179801c734749a04d4b4Aditya Kali return 0; 494f239fefc14226f655477179801c734749a04d4b4Aditya Kali} 495198d20fc74a6124548b96e4c14c38ff8d5a95ae5Niu 496198d20fc74a6124548b96e4c14c38ff8d5a95ae5Niustruct scan_dquots_data { 4977943ccf5f2fa76f1dc164ddd1ffd5044a1dca31aAditya Kali dict_t *quota_dict; 4987943ccf5f2fa76f1dc164ddd1ffd5044a1dca31aAditya Kali int update_limits; /* update limits from disk */ 4997943ccf5f2fa76f1dc164ddd1ffd5044a1dca31aAditya Kali int update_usage; 5007943ccf5f2fa76f1dc164ddd1ffd5044a1dca31aAditya Kali int usage_is_inconsistent; 501198d20fc74a6124548b96e4c14c38ff8d5a95ae5Niu}; 502198d20fc74a6124548b96e4c14c38ff8d5a95ae5Niu 503198d20fc74a6124548b96e4c14c38ff8d5a95ae5Niustatic int scan_dquots_callback(struct dquot *dquot, void *cb_data) 504198d20fc74a6124548b96e4c14c38ff8d5a95ae5Niu{ 5057943ccf5f2fa76f1dc164ddd1ffd5044a1dca31aAditya Kali struct scan_dquots_data *scan_data = cb_data; 5067943ccf5f2fa76f1dc164ddd1ffd5044a1dca31aAditya Kali dict_t *quota_dict = scan_data->quota_dict; 507198d20fc74a6124548b96e4c14c38ff8d5a95ae5Niu struct dquot *dq; 508198d20fc74a6124548b96e4c14c38ff8d5a95ae5Niu 5097943ccf5f2fa76f1dc164ddd1ffd5044a1dca31aAditya Kali dq = get_dq(quota_dict, dquot->dq_id); 510198d20fc74a6124548b96e4c14c38ff8d5a95ae5Niu dq->dq_id = dquot->dq_id; 51168ba77caa72aa91eb9473e624657c16cda8c361dTheodore Ts'o dq->dq_flags |= DQF_SEEN; 5127943ccf5f2fa76f1dc164ddd1ffd5044a1dca31aAditya Kali 513a0811c1a0ea18d4aebb4a16e7189501b80d4bc77Theodore Ts'o print_dquot("mem", dq); 514a0811c1a0ea18d4aebb4a16e7189501b80d4bc77Theodore Ts'o print_dquot("dsk", dquot); 515a0811c1a0ea18d4aebb4a16e7189501b80d4bc77Theodore Ts'o 5167943ccf5f2fa76f1dc164ddd1ffd5044a1dca31aAditya Kali /* Check if there is inconsistancy. */ 5177943ccf5f2fa76f1dc164ddd1ffd5044a1dca31aAditya Kali if (dq->dq_dqb.dqb_curspace != dquot->dq_dqb.dqb_curspace || 5187943ccf5f2fa76f1dc164ddd1ffd5044a1dca31aAditya Kali dq->dq_dqb.dqb_curinodes != dquot->dq_dqb.dqb_curinodes) { 5197943ccf5f2fa76f1dc164ddd1ffd5044a1dca31aAditya Kali scan_data->usage_is_inconsistent = 1; 5205027751530980c61e313d265b1367fee90589cf4Aditya Kali fprintf(stderr, "[QUOTA WARNING] Usage inconsistent for ID %d:" 5215027751530980c61e313d265b1367fee90589cf4Aditya Kali "actual (%llu, %llu) != expected (%llu, %llu)\n", 5220ce0172984c807d3366e8db6e2a2b6ecae314832Andreas Dilger dq->dq_id, (long long)dq->dq_dqb.dqb_curspace, 5230ce0172984c807d3366e8db6e2a2b6ecae314832Andreas Dilger (long long)dq->dq_dqb.dqb_curinodes, 5240ce0172984c807d3366e8db6e2a2b6ecae314832Andreas Dilger (long long)dquot->dq_dqb.dqb_curspace, 5250ce0172984c807d3366e8db6e2a2b6ecae314832Andreas Dilger (long long)dquot->dq_dqb.dqb_curinodes); 5267943ccf5f2fa76f1dc164ddd1ffd5044a1dca31aAditya Kali } 5277943ccf5f2fa76f1dc164ddd1ffd5044a1dca31aAditya Kali 5287943ccf5f2fa76f1dc164ddd1ffd5044a1dca31aAditya Kali if (scan_data->update_limits) { 529198d20fc74a6124548b96e4c14c38ff8d5a95ae5Niu dq->dq_dqb.dqb_ihardlimit = dquot->dq_dqb.dqb_ihardlimit; 530198d20fc74a6124548b96e4c14c38ff8d5a95ae5Niu dq->dq_dqb.dqb_isoftlimit = dquot->dq_dqb.dqb_isoftlimit; 531198d20fc74a6124548b96e4c14c38ff8d5a95ae5Niu dq->dq_dqb.dqb_bhardlimit = dquot->dq_dqb.dqb_bhardlimit; 532198d20fc74a6124548b96e4c14c38ff8d5a95ae5Niu dq->dq_dqb.dqb_bsoftlimit = dquot->dq_dqb.dqb_bsoftlimit; 533198d20fc74a6124548b96e4c14c38ff8d5a95ae5Niu } 5347943ccf5f2fa76f1dc164ddd1ffd5044a1dca31aAditya Kali 5357943ccf5f2fa76f1dc164ddd1ffd5044a1dca31aAditya Kali if (scan_data->update_usage) { 5367943ccf5f2fa76f1dc164ddd1ffd5044a1dca31aAditya Kali dq->dq_dqb.dqb_curspace = dquot->dq_dqb.dqb_curspace; 5377943ccf5f2fa76f1dc164ddd1ffd5044a1dca31aAditya Kali dq->dq_dqb.dqb_curinodes = dquot->dq_dqb.dqb_curinodes; 5387943ccf5f2fa76f1dc164ddd1ffd5044a1dca31aAditya Kali } 5397943ccf5f2fa76f1dc164ddd1ffd5044a1dca31aAditya Kali 540198d20fc74a6124548b96e4c14c38ff8d5a95ae5Niu return 0; 541198d20fc74a6124548b96e4c14c38ff8d5a95ae5Niu} 542198d20fc74a6124548b96e4c14c38ff8d5a95ae5Niu 543198d20fc74a6124548b96e4c14c38ff8d5a95ae5Niu/* 544198d20fc74a6124548b96e4c14c38ff8d5a95ae5Niu * Read all dquots from quota file into memory 545198d20fc74a6124548b96e4c14c38ff8d5a95ae5Niu */ 546198d20fc74a6124548b96e4c14c38ff8d5a95ae5Niustatic errcode_t quota_read_all_dquots(struct quota_handle *qh, 5477943ccf5f2fa76f1dc164ddd1ffd5044a1dca31aAditya Kali quota_ctx_t qctx, int update_limits) 548198d20fc74a6124548b96e4c14c38ff8d5a95ae5Niu{ 549198d20fc74a6124548b96e4c14c38ff8d5a95ae5Niu struct scan_dquots_data scan_data; 550198d20fc74a6124548b96e4c14c38ff8d5a95ae5Niu 5517943ccf5f2fa76f1dc164ddd1ffd5044a1dca31aAditya Kali scan_data.quota_dict = qctx->quota_dict[qh->qh_type]; 5527943ccf5f2fa76f1dc164ddd1ffd5044a1dca31aAditya Kali scan_data.update_limits = update_limits; 5537943ccf5f2fa76f1dc164ddd1ffd5044a1dca31aAditya Kali scan_data.update_usage = 0; 554198d20fc74a6124548b96e4c14c38ff8d5a95ae5Niu 555198d20fc74a6124548b96e4c14c38ff8d5a95ae5Niu return qh->qh_ops->scan_dquots(qh, scan_dquots_callback, &scan_data); 556198d20fc74a6124548b96e4c14c38ff8d5a95ae5Niu} 557198d20fc74a6124548b96e4c14c38ff8d5a95ae5Niu 558198d20fc74a6124548b96e4c14c38ff8d5a95ae5Niu/* 559198d20fc74a6124548b96e4c14c38ff8d5a95ae5Niu * Write all memory dquots into quota file 560198d20fc74a6124548b96e4c14c38ff8d5a95ae5Niu */ 5610ce0172984c807d3366e8db6e2a2b6ecae314832Andreas Dilger#if 0 /* currently unused, but may be useful in the future? */ 562198d20fc74a6124548b96e4c14c38ff8d5a95ae5Niustatic errcode_t quota_write_all_dquots(struct quota_handle *qh, 563198d20fc74a6124548b96e4c14c38ff8d5a95ae5Niu quota_ctx_t qctx) 564198d20fc74a6124548b96e4c14c38ff8d5a95ae5Niu{ 565198d20fc74a6124548b96e4c14c38ff8d5a95ae5Niu errcode_t err; 566198d20fc74a6124548b96e4c14c38ff8d5a95ae5Niu 567198d20fc74a6124548b96e4c14c38ff8d5a95ae5Niu err = ext2fs_read_bitmaps(qctx->fs); 568198d20fc74a6124548b96e4c14c38ff8d5a95ae5Niu if (err) 569198d20fc74a6124548b96e4c14c38ff8d5a95ae5Niu return err; 570198d20fc74a6124548b96e4c14c38ff8d5a95ae5Niu write_dquots(qctx->quota_dict[qh->qh_type], qh); 571198d20fc74a6124548b96e4c14c38ff8d5a95ae5Niu ext2fs_mark_bb_dirty(qctx->fs); 572198d20fc74a6124548b96e4c14c38ff8d5a95ae5Niu qctx->fs->flags &= ~EXT2_FLAG_SUPER_ONLY; 573198d20fc74a6124548b96e4c14c38ff8d5a95ae5Niu ext2fs_write_bitmaps(qctx->fs); 574198d20fc74a6124548b96e4c14c38ff8d5a95ae5Niu return 0; 575198d20fc74a6124548b96e4c14c38ff8d5a95ae5Niu} 5760ce0172984c807d3366e8db6e2a2b6ecae314832Andreas Dilger#endif 577198d20fc74a6124548b96e4c14c38ff8d5a95ae5Niu 578198d20fc74a6124548b96e4c14c38ff8d5a95ae5Niu/* 5795027751530980c61e313d265b1367fee90589cf4Aditya Kali * Updates the in-memory quota limits from the given quota inode. 580198d20fc74a6124548b96e4c14c38ff8d5a95ae5Niu */ 5812d2d799c72610f4d9b4910e7f1516f11288e1cf1Li Xierrcode_t quota_update_limits(quota_ctx_t qctx, ext2_ino_t qf_ino, 5822d2d799c72610f4d9b4910e7f1516f11288e1cf1Li Xi enum quota_type qtype) 583198d20fc74a6124548b96e4c14c38ff8d5a95ae5Niu{ 584198d20fc74a6124548b96e4c14c38ff8d5a95ae5Niu struct quota_handle *qh; 585198d20fc74a6124548b96e4c14c38ff8d5a95ae5Niu errcode_t err; 586198d20fc74a6124548b96e4c14c38ff8d5a95ae5Niu 587198d20fc74a6124548b96e4c14c38ff8d5a95ae5Niu if (!qctx) 588198d20fc74a6124548b96e4c14c38ff8d5a95ae5Niu return 0; 589198d20fc74a6124548b96e4c14c38ff8d5a95ae5Niu 590198d20fc74a6124548b96e4c14c38ff8d5a95ae5Niu err = ext2fs_get_mem(sizeof(struct quota_handle), &qh); 591198d20fc74a6124548b96e4c14c38ff8d5a95ae5Niu if (err) { 592a701823a31505c5765d327d02bb14aa43fc34ae5Theodore Ts'o log_debug("Unable to allocate quota handle"); 593198d20fc74a6124548b96e4c14c38ff8d5a95ae5Niu return err; 594198d20fc74a6124548b96e4c14c38ff8d5a95ae5Niu } 595198d20fc74a6124548b96e4c14c38ff8d5a95ae5Niu 5962d2d799c72610f4d9b4910e7f1516f11288e1cf1Li Xi err = quota_file_open(qctx, qh, qf_ino, qtype, -1, 0); 597198d20fc74a6124548b96e4c14c38ff8d5a95ae5Niu if (err) { 598a701823a31505c5765d327d02bb14aa43fc34ae5Theodore Ts'o log_debug("Open quota file failed"); 599198d20fc74a6124548b96e4c14c38ff8d5a95ae5Niu goto out; 600198d20fc74a6124548b96e4c14c38ff8d5a95ae5Niu } 601198d20fc74a6124548b96e4c14c38ff8d5a95ae5Niu 602198d20fc74a6124548b96e4c14c38ff8d5a95ae5Niu quota_read_all_dquots(qh, qctx, 1); 603198d20fc74a6124548b96e4c14c38ff8d5a95ae5Niu 604cbc1280dc73bce297b9d7f7ff9b8a17f709ef2b1Theodore Ts'o err = quota_file_close(qctx, qh); 605198d20fc74a6124548b96e4c14c38ff8d5a95ae5Niu if (err) { 606a701823a31505c5765d327d02bb14aa43fc34ae5Theodore Ts'o log_debug("Cannot finish IO on new quotafile: %s", 607198d20fc74a6124548b96e4c14c38ff8d5a95ae5Niu strerror(errno)); 608198d20fc74a6124548b96e4c14c38ff8d5a95ae5Niu if (qh->qh_qf.e2_file) 609198d20fc74a6124548b96e4c14c38ff8d5a95ae5Niu ext2fs_file_close(qh->qh_qf.e2_file); 610198d20fc74a6124548b96e4c14c38ff8d5a95ae5Niu } 611198d20fc74a6124548b96e4c14c38ff8d5a95ae5Niuout: 612198d20fc74a6124548b96e4c14c38ff8d5a95ae5Niu ext2fs_free_mem(&qh); 613198d20fc74a6124548b96e4c14c38ff8d5a95ae5Niu return err; 614198d20fc74a6124548b96e4c14c38ff8d5a95ae5Niu} 6157943ccf5f2fa76f1dc164ddd1ffd5044a1dca31aAditya Kali 6167943ccf5f2fa76f1dc164ddd1ffd5044a1dca31aAditya Kali/* 6177943ccf5f2fa76f1dc164ddd1ffd5044a1dca31aAditya Kali * Compares the measured quota in qctx->quota_dict with that in the quota inode 6187943ccf5f2fa76f1dc164ddd1ffd5044a1dca31aAditya Kali * on disk and updates the limits in qctx->quota_dict. 'usage_inconsistent' is 6197943ccf5f2fa76f1dc164ddd1ffd5044a1dca31aAditya Kali * set to 1 if the supplied and on-disk quota usage values are not identical. 6207943ccf5f2fa76f1dc164ddd1ffd5044a1dca31aAditya Kali */ 6212d2d799c72610f4d9b4910e7f1516f11288e1cf1Li Xierrcode_t quota_compare_and_update(quota_ctx_t qctx, enum quota_type qtype, 6227943ccf5f2fa76f1dc164ddd1ffd5044a1dca31aAditya Kali int *usage_inconsistent) 6237943ccf5f2fa76f1dc164ddd1ffd5044a1dca31aAditya Kali{ 6247943ccf5f2fa76f1dc164ddd1ffd5044a1dca31aAditya Kali struct quota_handle qh; 6257943ccf5f2fa76f1dc164ddd1ffd5044a1dca31aAditya Kali struct scan_dquots_data scan_data; 62668ba77caa72aa91eb9473e624657c16cda8c361dTheodore Ts'o struct dquot *dq; 62768ba77caa72aa91eb9473e624657c16cda8c361dTheodore Ts'o dnode_t *n; 62868ba77caa72aa91eb9473e624657c16cda8c361dTheodore Ts'o dict_t *dict = qctx->quota_dict[qtype]; 6297943ccf5f2fa76f1dc164ddd1ffd5044a1dca31aAditya Kali errcode_t err = 0; 6307943ccf5f2fa76f1dc164ddd1ffd5044a1dca31aAditya Kali 63168ba77caa72aa91eb9473e624657c16cda8c361dTheodore Ts'o if (!dict) 6327943ccf5f2fa76f1dc164ddd1ffd5044a1dca31aAditya Kali goto out; 6337943ccf5f2fa76f1dc164ddd1ffd5044a1dca31aAditya Kali 634cbc1280dc73bce297b9d7f7ff9b8a17f709ef2b1Theodore Ts'o err = quota_file_open(qctx, &qh, 0, qtype, -1, 0); 6357943ccf5f2fa76f1dc164ddd1ffd5044a1dca31aAditya Kali if (err) { 636a701823a31505c5765d327d02bb14aa43fc34ae5Theodore Ts'o log_debug("Open quota file failed"); 6377943ccf5f2fa76f1dc164ddd1ffd5044a1dca31aAditya Kali goto out; 6387943ccf5f2fa76f1dc164ddd1ffd5044a1dca31aAditya Kali } 6397943ccf5f2fa76f1dc164ddd1ffd5044a1dca31aAditya Kali 6407943ccf5f2fa76f1dc164ddd1ffd5044a1dca31aAditya Kali scan_data.quota_dict = qctx->quota_dict[qtype]; 6417943ccf5f2fa76f1dc164ddd1ffd5044a1dca31aAditya Kali scan_data.update_limits = 1; 6427943ccf5f2fa76f1dc164ddd1ffd5044a1dca31aAditya Kali scan_data.update_usage = 0; 6437943ccf5f2fa76f1dc164ddd1ffd5044a1dca31aAditya Kali scan_data.usage_is_inconsistent = 0; 6447943ccf5f2fa76f1dc164ddd1ffd5044a1dca31aAditya Kali err = qh.qh_ops->scan_dquots(&qh, scan_dquots_callback, &scan_data); 6457943ccf5f2fa76f1dc164ddd1ffd5044a1dca31aAditya Kali if (err) { 646a701823a31505c5765d327d02bb14aa43fc34ae5Theodore Ts'o log_debug("Error scanning dquots"); 6474af2b156ffa2d50ebfc9207e667d18d5a7a1ae45Theodore Ts'o goto out_close_qh; 6487943ccf5f2fa76f1dc164ddd1ffd5044a1dca31aAditya Kali } 64968ba77caa72aa91eb9473e624657c16cda8c361dTheodore Ts'o 65068ba77caa72aa91eb9473e624657c16cda8c361dTheodore Ts'o for (n = dict_first(dict); n; n = dict_next(dict, n)) { 65168ba77caa72aa91eb9473e624657c16cda8c361dTheodore Ts'o dq = dnode_get(n); 65268ba77caa72aa91eb9473e624657c16cda8c361dTheodore Ts'o if (!dq) 65368ba77caa72aa91eb9473e624657c16cda8c361dTheodore Ts'o continue; 65468ba77caa72aa91eb9473e624657c16cda8c361dTheodore Ts'o if ((dq->dq_flags & DQF_SEEN) == 0) { 65568ba77caa72aa91eb9473e624657c16cda8c361dTheodore Ts'o fprintf(stderr, "[QUOTA WARNING] " 65668ba77caa72aa91eb9473e624657c16cda8c361dTheodore Ts'o "Missing quota entry ID %d\n", dq->dq_id); 65768ba77caa72aa91eb9473e624657c16cda8c361dTheodore Ts'o scan_data.usage_is_inconsistent = 1; 65868ba77caa72aa91eb9473e624657c16cda8c361dTheodore Ts'o } 65968ba77caa72aa91eb9473e624657c16cda8c361dTheodore Ts'o } 6607943ccf5f2fa76f1dc164ddd1ffd5044a1dca31aAditya Kali *usage_inconsistent = scan_data.usage_is_inconsistent; 6617943ccf5f2fa76f1dc164ddd1ffd5044a1dca31aAditya Kali 6624af2b156ffa2d50ebfc9207e667d18d5a7a1ae45Theodore Ts'oout_close_qh: 663cbc1280dc73bce297b9d7f7ff9b8a17f709ef2b1Theodore Ts'o err = quota_file_close(qctx, &qh); 6644af2b156ffa2d50ebfc9207e667d18d5a7a1ae45Theodore Ts'o if (err) { 665a701823a31505c5765d327d02bb14aa43fc34ae5Theodore Ts'o log_debug("Cannot close quotafile: %s", error_message(errno)); 6664af2b156ffa2d50ebfc9207e667d18d5a7a1ae45Theodore Ts'o if (qh.qh_qf.e2_file) 6674af2b156ffa2d50ebfc9207e667d18d5a7a1ae45Theodore Ts'o ext2fs_file_close(qh.qh_qf.e2_file); 6684af2b156ffa2d50ebfc9207e667d18d5a7a1ae45Theodore Ts'o } 6697943ccf5f2fa76f1dc164ddd1ffd5044a1dca31aAditya Kaliout: 6707943ccf5f2fa76f1dc164ddd1ffd5044a1dca31aAditya Kali return err; 6717943ccf5f2fa76f1dc164ddd1ffd5044a1dca31aAditya Kali} 6722d2d799c72610f4d9b4910e7f1516f11288e1cf1Li Xi 673478360f50b68356849813f97db46fd156da5248eTheodore Ts'oint parse_quota_opts(const char *opts, int (*func)(char *)) 6742d2d799c72610f4d9b4910e7f1516f11288e1cf1Li Xi{ 6752d2d799c72610f4d9b4910e7f1516f11288e1cf1Li Xi char *buf, *token, *next, *p; 6762d2d799c72610f4d9b4910e7f1516f11288e1cf1Li Xi int len; 6772d2d799c72610f4d9b4910e7f1516f11288e1cf1Li Xi int ret = 0; 6782d2d799c72610f4d9b4910e7f1516f11288e1cf1Li Xi 6792d2d799c72610f4d9b4910e7f1516f11288e1cf1Li Xi len = strlen(opts); 6802d2d799c72610f4d9b4910e7f1516f11288e1cf1Li Xi buf = malloc(len + 1); 6812d2d799c72610f4d9b4910e7f1516f11288e1cf1Li Xi if (!buf) { 6822d2d799c72610f4d9b4910e7f1516f11288e1cf1Li Xi fprintf(stderr, 6832d2d799c72610f4d9b4910e7f1516f11288e1cf1Li Xi "Couldn't allocate memory to parse quota options!\n"); 6842d2d799c72610f4d9b4910e7f1516f11288e1cf1Li Xi return -ENOMEM; 6852d2d799c72610f4d9b4910e7f1516f11288e1cf1Li Xi } 6862d2d799c72610f4d9b4910e7f1516f11288e1cf1Li Xi strcpy(buf, opts); 6872d2d799c72610f4d9b4910e7f1516f11288e1cf1Li Xi for (token = buf; token && *token; token = next) { 6882d2d799c72610f4d9b4910e7f1516f11288e1cf1Li Xi p = strchr(token, ','); 6892d2d799c72610f4d9b4910e7f1516f11288e1cf1Li Xi next = 0; 6902d2d799c72610f4d9b4910e7f1516f11288e1cf1Li Xi if (p) { 6912d2d799c72610f4d9b4910e7f1516f11288e1cf1Li Xi *p = 0; 6922d2d799c72610f4d9b4910e7f1516f11288e1cf1Li Xi next = p + 1; 6932d2d799c72610f4d9b4910e7f1516f11288e1cf1Li Xi } 694478360f50b68356849813f97db46fd156da5248eTheodore Ts'o ret = func(token); 6952d2d799c72610f4d9b4910e7f1516f11288e1cf1Li Xi if (ret) 6962d2d799c72610f4d9b4910e7f1516f11288e1cf1Li Xi break; 6972d2d799c72610f4d9b4910e7f1516f11288e1cf1Li Xi } 6982d2d799c72610f4d9b4910e7f1516f11288e1cf1Li Xi free(buf); 6992d2d799c72610f4d9b4910e7f1516f11288e1cf1Li Xi return ret; 7002d2d799c72610f4d9b4910e7f1516f11288e1cf1Li Xi} 701