18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Implementation of the diskquota system for the LINUX operating system. QUOTA 48c2ecf20Sopenharmony_ci * is implemented using the BSD system call interface as the means of 58c2ecf20Sopenharmony_ci * communication with the user level. This file contains the generic routines 68c2ecf20Sopenharmony_ci * called by the different filesystems on allocation of an inode or block. 78c2ecf20Sopenharmony_ci * These routines take care of the administration needed to have a consistent 88c2ecf20Sopenharmony_ci * diskquota tracking system. The ideas of both user and group quotas are based 98c2ecf20Sopenharmony_ci * on the Melbourne quota system as used on BSD derived systems. The internal 108c2ecf20Sopenharmony_ci * implementation is based on one of the several variants of the LINUX 118c2ecf20Sopenharmony_ci * inode-subsystem with added complexity of the diskquota system. 128c2ecf20Sopenharmony_ci * 138c2ecf20Sopenharmony_ci * Author: Marco van Wieringen <mvw@planets.elm.net> 148c2ecf20Sopenharmony_ci * 158c2ecf20Sopenharmony_ci * Fixes: Dmitry Gorodchanin <pgmdsg@ibi.com>, 11 Feb 96 168c2ecf20Sopenharmony_ci * 178c2ecf20Sopenharmony_ci * Revised list management to avoid races 188c2ecf20Sopenharmony_ci * -- Bill Hawes, <whawes@star.net>, 9/98 198c2ecf20Sopenharmony_ci * 208c2ecf20Sopenharmony_ci * Fixed races in dquot_transfer(), dqget() and dquot_alloc_...(). 218c2ecf20Sopenharmony_ci * As the consequence the locking was moved from dquot_decr_...(), 228c2ecf20Sopenharmony_ci * dquot_incr_...() to calling functions. 238c2ecf20Sopenharmony_ci * invalidate_dquots() now writes modified dquots. 248c2ecf20Sopenharmony_ci * Serialized quota_off() and quota_on() for mount point. 258c2ecf20Sopenharmony_ci * Fixed a few bugs in grow_dquots(). 268c2ecf20Sopenharmony_ci * Fixed deadlock in write_dquot() - we no longer account quotas on 278c2ecf20Sopenharmony_ci * quota files 288c2ecf20Sopenharmony_ci * remove_dquot_ref() moved to inode.c - it now traverses through inodes 298c2ecf20Sopenharmony_ci * add_dquot_ref() restarts after blocking 308c2ecf20Sopenharmony_ci * Added check for bogus uid and fixed check for group in quotactl. 318c2ecf20Sopenharmony_ci * Jan Kara, <jack@suse.cz>, sponsored by SuSE CR, 10-11/99 328c2ecf20Sopenharmony_ci * 338c2ecf20Sopenharmony_ci * Used struct list_head instead of own list struct 348c2ecf20Sopenharmony_ci * Invalidation of referenced dquots is no longer possible 358c2ecf20Sopenharmony_ci * Improved free_dquots list management 368c2ecf20Sopenharmony_ci * Quota and i_blocks are now updated in one place to avoid races 378c2ecf20Sopenharmony_ci * Warnings are now delayed so we won't block in critical section 388c2ecf20Sopenharmony_ci * Write updated not to require dquot lock 398c2ecf20Sopenharmony_ci * Jan Kara, <jack@suse.cz>, 9/2000 408c2ecf20Sopenharmony_ci * 418c2ecf20Sopenharmony_ci * Added dynamic quota structure allocation 428c2ecf20Sopenharmony_ci * Jan Kara <jack@suse.cz> 12/2000 438c2ecf20Sopenharmony_ci * 448c2ecf20Sopenharmony_ci * Rewritten quota interface. Implemented new quota format and 458c2ecf20Sopenharmony_ci * formats registering. 468c2ecf20Sopenharmony_ci * Jan Kara, <jack@suse.cz>, 2001,2002 478c2ecf20Sopenharmony_ci * 488c2ecf20Sopenharmony_ci * New SMP locking. 498c2ecf20Sopenharmony_ci * Jan Kara, <jack@suse.cz>, 10/2002 508c2ecf20Sopenharmony_ci * 518c2ecf20Sopenharmony_ci * Added journalled quota support, fix lock inversion problems 528c2ecf20Sopenharmony_ci * Jan Kara, <jack@suse.cz>, 2003,2004 538c2ecf20Sopenharmony_ci * 548c2ecf20Sopenharmony_ci * (C) Copyright 1994 - 1997 Marco van Wieringen 558c2ecf20Sopenharmony_ci */ 568c2ecf20Sopenharmony_ci 578c2ecf20Sopenharmony_ci#include <linux/errno.h> 588c2ecf20Sopenharmony_ci#include <linux/kernel.h> 598c2ecf20Sopenharmony_ci#include <linux/fs.h> 608c2ecf20Sopenharmony_ci#include <linux/mount.h> 618c2ecf20Sopenharmony_ci#include <linux/mm.h> 628c2ecf20Sopenharmony_ci#include <linux/time.h> 638c2ecf20Sopenharmony_ci#include <linux/types.h> 648c2ecf20Sopenharmony_ci#include <linux/string.h> 658c2ecf20Sopenharmony_ci#include <linux/fcntl.h> 668c2ecf20Sopenharmony_ci#include <linux/stat.h> 678c2ecf20Sopenharmony_ci#include <linux/tty.h> 688c2ecf20Sopenharmony_ci#include <linux/file.h> 698c2ecf20Sopenharmony_ci#include <linux/slab.h> 708c2ecf20Sopenharmony_ci#include <linux/sysctl.h> 718c2ecf20Sopenharmony_ci#include <linux/init.h> 728c2ecf20Sopenharmony_ci#include <linux/module.h> 738c2ecf20Sopenharmony_ci#include <linux/proc_fs.h> 748c2ecf20Sopenharmony_ci#include <linux/security.h> 758c2ecf20Sopenharmony_ci#include <linux/sched.h> 768c2ecf20Sopenharmony_ci#include <linux/cred.h> 778c2ecf20Sopenharmony_ci#include <linux/kmod.h> 788c2ecf20Sopenharmony_ci#include <linux/namei.h> 798c2ecf20Sopenharmony_ci#include <linux/capability.h> 808c2ecf20Sopenharmony_ci#include <linux/quotaops.h> 818c2ecf20Sopenharmony_ci#include <linux/blkdev.h> 828c2ecf20Sopenharmony_ci#include <linux/sched/mm.h> 838c2ecf20Sopenharmony_ci#include "../internal.h" /* ugh */ 848c2ecf20Sopenharmony_ci 858c2ecf20Sopenharmony_ci#include <linux/uaccess.h> 868c2ecf20Sopenharmony_ci 878c2ecf20Sopenharmony_ci/* 888c2ecf20Sopenharmony_ci * There are five quota SMP locks: 898c2ecf20Sopenharmony_ci * * dq_list_lock protects all lists with quotas and quota formats. 908c2ecf20Sopenharmony_ci * * dquot->dq_dqb_lock protects data from dq_dqb 918c2ecf20Sopenharmony_ci * * inode->i_lock protects inode->i_blocks, i_bytes and also guards 928c2ecf20Sopenharmony_ci * consistency of dquot->dq_dqb with inode->i_blocks, i_bytes so that 938c2ecf20Sopenharmony_ci * dquot_transfer() can stabilize amount it transfers 948c2ecf20Sopenharmony_ci * * dq_data_lock protects mem_dqinfo structures and modifications of dquot 958c2ecf20Sopenharmony_ci * pointers in the inode 968c2ecf20Sopenharmony_ci * * dq_state_lock protects modifications of quota state (on quotaon and 978c2ecf20Sopenharmony_ci * quotaoff) and readers who care about latest values take it as well. 988c2ecf20Sopenharmony_ci * 998c2ecf20Sopenharmony_ci * The spinlock ordering is hence: 1008c2ecf20Sopenharmony_ci * dq_data_lock > dq_list_lock > i_lock > dquot->dq_dqb_lock, 1018c2ecf20Sopenharmony_ci * dq_list_lock > dq_state_lock 1028c2ecf20Sopenharmony_ci * 1038c2ecf20Sopenharmony_ci * Note that some things (eg. sb pointer, type, id) doesn't change during 1048c2ecf20Sopenharmony_ci * the life of the dquot structure and so needn't to be protected by a lock 1058c2ecf20Sopenharmony_ci * 1068c2ecf20Sopenharmony_ci * Operation accessing dquots via inode pointers are protected by dquot_srcu. 1078c2ecf20Sopenharmony_ci * Operation of reading pointer needs srcu_read_lock(&dquot_srcu), and 1088c2ecf20Sopenharmony_ci * synchronize_srcu(&dquot_srcu) is called after clearing pointers from 1098c2ecf20Sopenharmony_ci * inode and before dropping dquot references to avoid use of dquots after 1108c2ecf20Sopenharmony_ci * they are freed. dq_data_lock is used to serialize the pointer setting and 1118c2ecf20Sopenharmony_ci * clearing operations. 1128c2ecf20Sopenharmony_ci * Special care needs to be taken about S_NOQUOTA inode flag (marking that 1138c2ecf20Sopenharmony_ci * inode is a quota file). Functions adding pointers from inode to dquots have 1148c2ecf20Sopenharmony_ci * to check this flag under dq_data_lock and then (if S_NOQUOTA is not set) they 1158c2ecf20Sopenharmony_ci * have to do all pointer modifications before dropping dq_data_lock. This makes 1168c2ecf20Sopenharmony_ci * sure they cannot race with quotaon which first sets S_NOQUOTA flag and 1178c2ecf20Sopenharmony_ci * then drops all pointers to dquots from an inode. 1188c2ecf20Sopenharmony_ci * 1198c2ecf20Sopenharmony_ci * Each dquot has its dq_lock mutex. Dquot is locked when it is being read to 1208c2ecf20Sopenharmony_ci * memory (or space for it is being allocated) on the first dqget(), when it is 1218c2ecf20Sopenharmony_ci * being written out, and when it is being released on the last dqput(). The 1228c2ecf20Sopenharmony_ci * allocation and release operations are serialized by the dq_lock and by 1238c2ecf20Sopenharmony_ci * checking the use count in dquot_release(). 1248c2ecf20Sopenharmony_ci * 1258c2ecf20Sopenharmony_ci * Lock ordering (including related VFS locks) is the following: 1268c2ecf20Sopenharmony_ci * s_umount > i_mutex > journal_lock > dquot->dq_lock > dqio_sem 1278c2ecf20Sopenharmony_ci */ 1288c2ecf20Sopenharmony_ci 1298c2ecf20Sopenharmony_cistatic __cacheline_aligned_in_smp DEFINE_SPINLOCK(dq_list_lock); 1308c2ecf20Sopenharmony_cistatic __cacheline_aligned_in_smp DEFINE_SPINLOCK(dq_state_lock); 1318c2ecf20Sopenharmony_ci__cacheline_aligned_in_smp DEFINE_SPINLOCK(dq_data_lock); 1328c2ecf20Sopenharmony_ciEXPORT_SYMBOL(dq_data_lock); 1338c2ecf20Sopenharmony_ciDEFINE_STATIC_SRCU(dquot_srcu); 1348c2ecf20Sopenharmony_ci 1358c2ecf20Sopenharmony_cistatic DECLARE_WAIT_QUEUE_HEAD(dquot_ref_wq); 1368c2ecf20Sopenharmony_ci 1378c2ecf20Sopenharmony_civoid __quota_error(struct super_block *sb, const char *func, 1388c2ecf20Sopenharmony_ci const char *fmt, ...) 1398c2ecf20Sopenharmony_ci{ 1408c2ecf20Sopenharmony_ci if (printk_ratelimit()) { 1418c2ecf20Sopenharmony_ci va_list args; 1428c2ecf20Sopenharmony_ci struct va_format vaf; 1438c2ecf20Sopenharmony_ci 1448c2ecf20Sopenharmony_ci va_start(args, fmt); 1458c2ecf20Sopenharmony_ci 1468c2ecf20Sopenharmony_ci vaf.fmt = fmt; 1478c2ecf20Sopenharmony_ci vaf.va = &args; 1488c2ecf20Sopenharmony_ci 1498c2ecf20Sopenharmony_ci printk(KERN_ERR "Quota error (device %s): %s: %pV\n", 1508c2ecf20Sopenharmony_ci sb->s_id, func, &vaf); 1518c2ecf20Sopenharmony_ci 1528c2ecf20Sopenharmony_ci va_end(args); 1538c2ecf20Sopenharmony_ci } 1548c2ecf20Sopenharmony_ci} 1558c2ecf20Sopenharmony_ciEXPORT_SYMBOL(__quota_error); 1568c2ecf20Sopenharmony_ci 1578c2ecf20Sopenharmony_ci#if defined(CONFIG_QUOTA_DEBUG) || defined(CONFIG_PRINT_QUOTA_WARNING) 1588c2ecf20Sopenharmony_cistatic char *quotatypes[] = INITQFNAMES; 1598c2ecf20Sopenharmony_ci#endif 1608c2ecf20Sopenharmony_cistatic struct quota_format_type *quota_formats; /* List of registered formats */ 1618c2ecf20Sopenharmony_cistatic struct quota_module_name module_names[] = INIT_QUOTA_MODULE_NAMES; 1628c2ecf20Sopenharmony_ci 1638c2ecf20Sopenharmony_ci/* SLAB cache for dquot structures */ 1648c2ecf20Sopenharmony_cistatic struct kmem_cache *dquot_cachep; 1658c2ecf20Sopenharmony_ci 1668c2ecf20Sopenharmony_ciint register_quota_format(struct quota_format_type *fmt) 1678c2ecf20Sopenharmony_ci{ 1688c2ecf20Sopenharmony_ci spin_lock(&dq_list_lock); 1698c2ecf20Sopenharmony_ci fmt->qf_next = quota_formats; 1708c2ecf20Sopenharmony_ci quota_formats = fmt; 1718c2ecf20Sopenharmony_ci spin_unlock(&dq_list_lock); 1728c2ecf20Sopenharmony_ci return 0; 1738c2ecf20Sopenharmony_ci} 1748c2ecf20Sopenharmony_ciEXPORT_SYMBOL(register_quota_format); 1758c2ecf20Sopenharmony_ci 1768c2ecf20Sopenharmony_civoid unregister_quota_format(struct quota_format_type *fmt) 1778c2ecf20Sopenharmony_ci{ 1788c2ecf20Sopenharmony_ci struct quota_format_type **actqf; 1798c2ecf20Sopenharmony_ci 1808c2ecf20Sopenharmony_ci spin_lock(&dq_list_lock); 1818c2ecf20Sopenharmony_ci for (actqf = "a_formats; *actqf && *actqf != fmt; 1828c2ecf20Sopenharmony_ci actqf = &(*actqf)->qf_next) 1838c2ecf20Sopenharmony_ci ; 1848c2ecf20Sopenharmony_ci if (*actqf) 1858c2ecf20Sopenharmony_ci *actqf = (*actqf)->qf_next; 1868c2ecf20Sopenharmony_ci spin_unlock(&dq_list_lock); 1878c2ecf20Sopenharmony_ci} 1888c2ecf20Sopenharmony_ciEXPORT_SYMBOL(unregister_quota_format); 1898c2ecf20Sopenharmony_ci 1908c2ecf20Sopenharmony_cistatic struct quota_format_type *find_quota_format(int id) 1918c2ecf20Sopenharmony_ci{ 1928c2ecf20Sopenharmony_ci struct quota_format_type *actqf; 1938c2ecf20Sopenharmony_ci 1948c2ecf20Sopenharmony_ci spin_lock(&dq_list_lock); 1958c2ecf20Sopenharmony_ci for (actqf = quota_formats; actqf && actqf->qf_fmt_id != id; 1968c2ecf20Sopenharmony_ci actqf = actqf->qf_next) 1978c2ecf20Sopenharmony_ci ; 1988c2ecf20Sopenharmony_ci if (!actqf || !try_module_get(actqf->qf_owner)) { 1998c2ecf20Sopenharmony_ci int qm; 2008c2ecf20Sopenharmony_ci 2018c2ecf20Sopenharmony_ci spin_unlock(&dq_list_lock); 2028c2ecf20Sopenharmony_ci 2038c2ecf20Sopenharmony_ci for (qm = 0; module_names[qm].qm_fmt_id && 2048c2ecf20Sopenharmony_ci module_names[qm].qm_fmt_id != id; qm++) 2058c2ecf20Sopenharmony_ci ; 2068c2ecf20Sopenharmony_ci if (!module_names[qm].qm_fmt_id || 2078c2ecf20Sopenharmony_ci request_module(module_names[qm].qm_mod_name)) 2088c2ecf20Sopenharmony_ci return NULL; 2098c2ecf20Sopenharmony_ci 2108c2ecf20Sopenharmony_ci spin_lock(&dq_list_lock); 2118c2ecf20Sopenharmony_ci for (actqf = quota_formats; actqf && actqf->qf_fmt_id != id; 2128c2ecf20Sopenharmony_ci actqf = actqf->qf_next) 2138c2ecf20Sopenharmony_ci ; 2148c2ecf20Sopenharmony_ci if (actqf && !try_module_get(actqf->qf_owner)) 2158c2ecf20Sopenharmony_ci actqf = NULL; 2168c2ecf20Sopenharmony_ci } 2178c2ecf20Sopenharmony_ci spin_unlock(&dq_list_lock); 2188c2ecf20Sopenharmony_ci return actqf; 2198c2ecf20Sopenharmony_ci} 2208c2ecf20Sopenharmony_ci 2218c2ecf20Sopenharmony_cistatic void put_quota_format(struct quota_format_type *fmt) 2228c2ecf20Sopenharmony_ci{ 2238c2ecf20Sopenharmony_ci module_put(fmt->qf_owner); 2248c2ecf20Sopenharmony_ci} 2258c2ecf20Sopenharmony_ci 2268c2ecf20Sopenharmony_ci/* 2278c2ecf20Sopenharmony_ci * Dquot List Management: 2288c2ecf20Sopenharmony_ci * The quota code uses five lists for dquot management: the inuse_list, 2298c2ecf20Sopenharmony_ci * releasing_dquots, free_dquots, dqi_dirty_list, and dquot_hash[] array. 2308c2ecf20Sopenharmony_ci * A single dquot structure may be on some of those lists, depending on 2318c2ecf20Sopenharmony_ci * its current state. 2328c2ecf20Sopenharmony_ci * 2338c2ecf20Sopenharmony_ci * All dquots are placed to the end of inuse_list when first created, and this 2348c2ecf20Sopenharmony_ci * list is used for invalidate operation, which must look at every dquot. 2358c2ecf20Sopenharmony_ci * 2368c2ecf20Sopenharmony_ci * When the last reference of a dquot is dropped, the dquot is added to 2378c2ecf20Sopenharmony_ci * releasing_dquots. We'll then queue work item which will call 2388c2ecf20Sopenharmony_ci * synchronize_srcu() and after that perform the final cleanup of all the 2398c2ecf20Sopenharmony_ci * dquots on the list. Each cleaned up dquot is moved to free_dquots list. 2408c2ecf20Sopenharmony_ci * Both releasing_dquots and free_dquots use the dq_free list_head in the dquot 2418c2ecf20Sopenharmony_ci * struct. 2428c2ecf20Sopenharmony_ci * 2438c2ecf20Sopenharmony_ci * Unused and cleaned up dquots are in the free_dquots list and this list is 2448c2ecf20Sopenharmony_ci * searched whenever we need an available dquot. Dquots are removed from the 2458c2ecf20Sopenharmony_ci * list as soon as they are used again and dqstats.free_dquots gives the number 2468c2ecf20Sopenharmony_ci * of dquots on the list. When dquot is invalidated it's completely released 2478c2ecf20Sopenharmony_ci * from memory. 2488c2ecf20Sopenharmony_ci * 2498c2ecf20Sopenharmony_ci * Dirty dquots are added to the dqi_dirty_list of quota_info when mark 2508c2ecf20Sopenharmony_ci * dirtied, and this list is searched when writing dirty dquots back to 2518c2ecf20Sopenharmony_ci * quota file. Note that some filesystems do dirty dquot tracking on their 2528c2ecf20Sopenharmony_ci * own (e.g. in a journal) and thus don't use dqi_dirty_list. 2538c2ecf20Sopenharmony_ci * 2548c2ecf20Sopenharmony_ci * Dquots with a specific identity (device, type and id) are placed on 2558c2ecf20Sopenharmony_ci * one of the dquot_hash[] hash chains. The provides an efficient search 2568c2ecf20Sopenharmony_ci * mechanism to locate a specific dquot. 2578c2ecf20Sopenharmony_ci */ 2588c2ecf20Sopenharmony_ci 2598c2ecf20Sopenharmony_cistatic LIST_HEAD(inuse_list); 2608c2ecf20Sopenharmony_cistatic LIST_HEAD(free_dquots); 2618c2ecf20Sopenharmony_cistatic LIST_HEAD(releasing_dquots); 2628c2ecf20Sopenharmony_cistatic unsigned int dq_hash_bits, dq_hash_mask; 2638c2ecf20Sopenharmony_cistatic struct hlist_head *dquot_hash; 2648c2ecf20Sopenharmony_ci 2658c2ecf20Sopenharmony_cistruct dqstats dqstats; 2668c2ecf20Sopenharmony_ciEXPORT_SYMBOL(dqstats); 2678c2ecf20Sopenharmony_ci 2688c2ecf20Sopenharmony_cistatic qsize_t inode_get_rsv_space(struct inode *inode); 2698c2ecf20Sopenharmony_cistatic qsize_t __inode_get_rsv_space(struct inode *inode); 2708c2ecf20Sopenharmony_cistatic int __dquot_initialize(struct inode *inode, int type); 2718c2ecf20Sopenharmony_ci 2728c2ecf20Sopenharmony_cistatic void quota_release_workfn(struct work_struct *work); 2738c2ecf20Sopenharmony_cistatic DECLARE_DELAYED_WORK(quota_release_work, quota_release_workfn); 2748c2ecf20Sopenharmony_ci 2758c2ecf20Sopenharmony_cistatic inline unsigned int 2768c2ecf20Sopenharmony_cihashfn(const struct super_block *sb, struct kqid qid) 2778c2ecf20Sopenharmony_ci{ 2788c2ecf20Sopenharmony_ci unsigned int id = from_kqid(&init_user_ns, qid); 2798c2ecf20Sopenharmony_ci int type = qid.type; 2808c2ecf20Sopenharmony_ci unsigned long tmp; 2818c2ecf20Sopenharmony_ci 2828c2ecf20Sopenharmony_ci tmp = (((unsigned long)sb>>L1_CACHE_SHIFT) ^ id) * (MAXQUOTAS - type); 2838c2ecf20Sopenharmony_ci return (tmp + (tmp >> dq_hash_bits)) & dq_hash_mask; 2848c2ecf20Sopenharmony_ci} 2858c2ecf20Sopenharmony_ci 2868c2ecf20Sopenharmony_ci/* 2878c2ecf20Sopenharmony_ci * Following list functions expect dq_list_lock to be held 2888c2ecf20Sopenharmony_ci */ 2898c2ecf20Sopenharmony_cistatic inline void insert_dquot_hash(struct dquot *dquot) 2908c2ecf20Sopenharmony_ci{ 2918c2ecf20Sopenharmony_ci struct hlist_head *head; 2928c2ecf20Sopenharmony_ci head = dquot_hash + hashfn(dquot->dq_sb, dquot->dq_id); 2938c2ecf20Sopenharmony_ci hlist_add_head(&dquot->dq_hash, head); 2948c2ecf20Sopenharmony_ci} 2958c2ecf20Sopenharmony_ci 2968c2ecf20Sopenharmony_cistatic inline void remove_dquot_hash(struct dquot *dquot) 2978c2ecf20Sopenharmony_ci{ 2988c2ecf20Sopenharmony_ci hlist_del_init(&dquot->dq_hash); 2998c2ecf20Sopenharmony_ci} 3008c2ecf20Sopenharmony_ci 3018c2ecf20Sopenharmony_cistatic struct dquot *find_dquot(unsigned int hashent, struct super_block *sb, 3028c2ecf20Sopenharmony_ci struct kqid qid) 3038c2ecf20Sopenharmony_ci{ 3048c2ecf20Sopenharmony_ci struct hlist_node *node; 3058c2ecf20Sopenharmony_ci struct dquot *dquot; 3068c2ecf20Sopenharmony_ci 3078c2ecf20Sopenharmony_ci hlist_for_each (node, dquot_hash+hashent) { 3088c2ecf20Sopenharmony_ci dquot = hlist_entry(node, struct dquot, dq_hash); 3098c2ecf20Sopenharmony_ci if (dquot->dq_sb == sb && qid_eq(dquot->dq_id, qid)) 3108c2ecf20Sopenharmony_ci return dquot; 3118c2ecf20Sopenharmony_ci } 3128c2ecf20Sopenharmony_ci return NULL; 3138c2ecf20Sopenharmony_ci} 3148c2ecf20Sopenharmony_ci 3158c2ecf20Sopenharmony_ci/* Add a dquot to the tail of the free list */ 3168c2ecf20Sopenharmony_cistatic inline void put_dquot_last(struct dquot *dquot) 3178c2ecf20Sopenharmony_ci{ 3188c2ecf20Sopenharmony_ci list_add_tail(&dquot->dq_free, &free_dquots); 3198c2ecf20Sopenharmony_ci dqstats_inc(DQST_FREE_DQUOTS); 3208c2ecf20Sopenharmony_ci} 3218c2ecf20Sopenharmony_ci 3228c2ecf20Sopenharmony_cistatic inline void put_releasing_dquots(struct dquot *dquot) 3238c2ecf20Sopenharmony_ci{ 3248c2ecf20Sopenharmony_ci list_add_tail(&dquot->dq_free, &releasing_dquots); 3258c2ecf20Sopenharmony_ci set_bit(DQ_RELEASING_B, &dquot->dq_flags); 3268c2ecf20Sopenharmony_ci} 3278c2ecf20Sopenharmony_ci 3288c2ecf20Sopenharmony_cistatic inline void remove_free_dquot(struct dquot *dquot) 3298c2ecf20Sopenharmony_ci{ 3308c2ecf20Sopenharmony_ci if (list_empty(&dquot->dq_free)) 3318c2ecf20Sopenharmony_ci return; 3328c2ecf20Sopenharmony_ci list_del_init(&dquot->dq_free); 3338c2ecf20Sopenharmony_ci if (!test_bit(DQ_RELEASING_B, &dquot->dq_flags)) 3348c2ecf20Sopenharmony_ci dqstats_dec(DQST_FREE_DQUOTS); 3358c2ecf20Sopenharmony_ci else 3368c2ecf20Sopenharmony_ci clear_bit(DQ_RELEASING_B, &dquot->dq_flags); 3378c2ecf20Sopenharmony_ci} 3388c2ecf20Sopenharmony_ci 3398c2ecf20Sopenharmony_cistatic inline void put_inuse(struct dquot *dquot) 3408c2ecf20Sopenharmony_ci{ 3418c2ecf20Sopenharmony_ci /* We add to the back of inuse list so we don't have to restart 3428c2ecf20Sopenharmony_ci * when traversing this list and we block */ 3438c2ecf20Sopenharmony_ci list_add_tail(&dquot->dq_inuse, &inuse_list); 3448c2ecf20Sopenharmony_ci dqstats_inc(DQST_ALLOC_DQUOTS); 3458c2ecf20Sopenharmony_ci} 3468c2ecf20Sopenharmony_ci 3478c2ecf20Sopenharmony_cistatic inline void remove_inuse(struct dquot *dquot) 3488c2ecf20Sopenharmony_ci{ 3498c2ecf20Sopenharmony_ci dqstats_dec(DQST_ALLOC_DQUOTS); 3508c2ecf20Sopenharmony_ci list_del(&dquot->dq_inuse); 3518c2ecf20Sopenharmony_ci} 3528c2ecf20Sopenharmony_ci/* 3538c2ecf20Sopenharmony_ci * End of list functions needing dq_list_lock 3548c2ecf20Sopenharmony_ci */ 3558c2ecf20Sopenharmony_ci 3568c2ecf20Sopenharmony_cistatic void wait_on_dquot(struct dquot *dquot) 3578c2ecf20Sopenharmony_ci{ 3588c2ecf20Sopenharmony_ci mutex_lock(&dquot->dq_lock); 3598c2ecf20Sopenharmony_ci mutex_unlock(&dquot->dq_lock); 3608c2ecf20Sopenharmony_ci} 3618c2ecf20Sopenharmony_ci 3628c2ecf20Sopenharmony_cistatic inline int dquot_active(struct dquot *dquot) 3638c2ecf20Sopenharmony_ci{ 3648c2ecf20Sopenharmony_ci return test_bit(DQ_ACTIVE_B, &dquot->dq_flags); 3658c2ecf20Sopenharmony_ci} 3668c2ecf20Sopenharmony_ci 3678c2ecf20Sopenharmony_cistatic inline int dquot_dirty(struct dquot *dquot) 3688c2ecf20Sopenharmony_ci{ 3698c2ecf20Sopenharmony_ci return test_bit(DQ_MOD_B, &dquot->dq_flags); 3708c2ecf20Sopenharmony_ci} 3718c2ecf20Sopenharmony_ci 3728c2ecf20Sopenharmony_cistatic inline int mark_dquot_dirty(struct dquot *dquot) 3738c2ecf20Sopenharmony_ci{ 3748c2ecf20Sopenharmony_ci return dquot->dq_sb->dq_op->mark_dirty(dquot); 3758c2ecf20Sopenharmony_ci} 3768c2ecf20Sopenharmony_ci 3778c2ecf20Sopenharmony_ci/* Mark dquot dirty in atomic manner, and return it's old dirty flag state */ 3788c2ecf20Sopenharmony_ciint dquot_mark_dquot_dirty(struct dquot *dquot) 3798c2ecf20Sopenharmony_ci{ 3808c2ecf20Sopenharmony_ci int ret = 1; 3818c2ecf20Sopenharmony_ci 3828c2ecf20Sopenharmony_ci if (!dquot_active(dquot)) 3838c2ecf20Sopenharmony_ci return 0; 3848c2ecf20Sopenharmony_ci 3858c2ecf20Sopenharmony_ci if (sb_dqopt(dquot->dq_sb)->flags & DQUOT_NOLIST_DIRTY) 3868c2ecf20Sopenharmony_ci return test_and_set_bit(DQ_MOD_B, &dquot->dq_flags); 3878c2ecf20Sopenharmony_ci 3888c2ecf20Sopenharmony_ci /* If quota is dirty already, we don't have to acquire dq_list_lock */ 3898c2ecf20Sopenharmony_ci if (dquot_dirty(dquot)) 3908c2ecf20Sopenharmony_ci return 1; 3918c2ecf20Sopenharmony_ci 3928c2ecf20Sopenharmony_ci spin_lock(&dq_list_lock); 3938c2ecf20Sopenharmony_ci if (!test_and_set_bit(DQ_MOD_B, &dquot->dq_flags)) { 3948c2ecf20Sopenharmony_ci list_add(&dquot->dq_dirty, &sb_dqopt(dquot->dq_sb)-> 3958c2ecf20Sopenharmony_ci info[dquot->dq_id.type].dqi_dirty_list); 3968c2ecf20Sopenharmony_ci ret = 0; 3978c2ecf20Sopenharmony_ci } 3988c2ecf20Sopenharmony_ci spin_unlock(&dq_list_lock); 3998c2ecf20Sopenharmony_ci return ret; 4008c2ecf20Sopenharmony_ci} 4018c2ecf20Sopenharmony_ciEXPORT_SYMBOL(dquot_mark_dquot_dirty); 4028c2ecf20Sopenharmony_ci 4038c2ecf20Sopenharmony_ci/* Dirtify all the dquots - this can block when journalling */ 4048c2ecf20Sopenharmony_cistatic inline int mark_all_dquot_dirty(struct dquot * const *dquots) 4058c2ecf20Sopenharmony_ci{ 4068c2ecf20Sopenharmony_ci int ret, err, cnt; 4078c2ecf20Sopenharmony_ci struct dquot *dquot; 4088c2ecf20Sopenharmony_ci 4098c2ecf20Sopenharmony_ci ret = err = 0; 4108c2ecf20Sopenharmony_ci for (cnt = 0; cnt < MAXQUOTAS; cnt++) { 4118c2ecf20Sopenharmony_ci dquot = srcu_dereference(dquots[cnt], &dquot_srcu); 4128c2ecf20Sopenharmony_ci if (dquot) 4138c2ecf20Sopenharmony_ci /* Even in case of error we have to continue */ 4148c2ecf20Sopenharmony_ci ret = mark_dquot_dirty(dquot); 4158c2ecf20Sopenharmony_ci if (!err) 4168c2ecf20Sopenharmony_ci err = ret; 4178c2ecf20Sopenharmony_ci } 4188c2ecf20Sopenharmony_ci return err; 4198c2ecf20Sopenharmony_ci} 4208c2ecf20Sopenharmony_ci 4218c2ecf20Sopenharmony_cistatic inline void dqput_all(struct dquot **dquot) 4228c2ecf20Sopenharmony_ci{ 4238c2ecf20Sopenharmony_ci unsigned int cnt; 4248c2ecf20Sopenharmony_ci 4258c2ecf20Sopenharmony_ci for (cnt = 0; cnt < MAXQUOTAS; cnt++) 4268c2ecf20Sopenharmony_ci dqput(dquot[cnt]); 4278c2ecf20Sopenharmony_ci} 4288c2ecf20Sopenharmony_ci 4298c2ecf20Sopenharmony_cistatic inline int clear_dquot_dirty(struct dquot *dquot) 4308c2ecf20Sopenharmony_ci{ 4318c2ecf20Sopenharmony_ci if (sb_dqopt(dquot->dq_sb)->flags & DQUOT_NOLIST_DIRTY) 4328c2ecf20Sopenharmony_ci return test_and_clear_bit(DQ_MOD_B, &dquot->dq_flags); 4338c2ecf20Sopenharmony_ci 4348c2ecf20Sopenharmony_ci spin_lock(&dq_list_lock); 4358c2ecf20Sopenharmony_ci if (!test_and_clear_bit(DQ_MOD_B, &dquot->dq_flags)) { 4368c2ecf20Sopenharmony_ci spin_unlock(&dq_list_lock); 4378c2ecf20Sopenharmony_ci return 0; 4388c2ecf20Sopenharmony_ci } 4398c2ecf20Sopenharmony_ci list_del_init(&dquot->dq_dirty); 4408c2ecf20Sopenharmony_ci spin_unlock(&dq_list_lock); 4418c2ecf20Sopenharmony_ci return 1; 4428c2ecf20Sopenharmony_ci} 4438c2ecf20Sopenharmony_ci 4448c2ecf20Sopenharmony_civoid mark_info_dirty(struct super_block *sb, int type) 4458c2ecf20Sopenharmony_ci{ 4468c2ecf20Sopenharmony_ci spin_lock(&dq_data_lock); 4478c2ecf20Sopenharmony_ci sb_dqopt(sb)->info[type].dqi_flags |= DQF_INFO_DIRTY; 4488c2ecf20Sopenharmony_ci spin_unlock(&dq_data_lock); 4498c2ecf20Sopenharmony_ci} 4508c2ecf20Sopenharmony_ciEXPORT_SYMBOL(mark_info_dirty); 4518c2ecf20Sopenharmony_ci 4528c2ecf20Sopenharmony_ci/* 4538c2ecf20Sopenharmony_ci * Read dquot from disk and alloc space for it 4548c2ecf20Sopenharmony_ci */ 4558c2ecf20Sopenharmony_ci 4568c2ecf20Sopenharmony_ciint dquot_acquire(struct dquot *dquot) 4578c2ecf20Sopenharmony_ci{ 4588c2ecf20Sopenharmony_ci int ret = 0, ret2 = 0; 4598c2ecf20Sopenharmony_ci unsigned int memalloc; 4608c2ecf20Sopenharmony_ci struct quota_info *dqopt = sb_dqopt(dquot->dq_sb); 4618c2ecf20Sopenharmony_ci 4628c2ecf20Sopenharmony_ci mutex_lock(&dquot->dq_lock); 4638c2ecf20Sopenharmony_ci memalloc = memalloc_nofs_save(); 4648c2ecf20Sopenharmony_ci if (!test_bit(DQ_READ_B, &dquot->dq_flags)) { 4658c2ecf20Sopenharmony_ci ret = dqopt->ops[dquot->dq_id.type]->read_dqblk(dquot); 4668c2ecf20Sopenharmony_ci if (ret < 0) 4678c2ecf20Sopenharmony_ci goto out_iolock; 4688c2ecf20Sopenharmony_ci } 4698c2ecf20Sopenharmony_ci /* Make sure flags update is visible after dquot has been filled */ 4708c2ecf20Sopenharmony_ci smp_mb__before_atomic(); 4718c2ecf20Sopenharmony_ci set_bit(DQ_READ_B, &dquot->dq_flags); 4728c2ecf20Sopenharmony_ci /* Instantiate dquot if needed */ 4738c2ecf20Sopenharmony_ci if (!dquot_active(dquot) && !dquot->dq_off) { 4748c2ecf20Sopenharmony_ci ret = dqopt->ops[dquot->dq_id.type]->commit_dqblk(dquot); 4758c2ecf20Sopenharmony_ci /* Write the info if needed */ 4768c2ecf20Sopenharmony_ci if (info_dirty(&dqopt->info[dquot->dq_id.type])) { 4778c2ecf20Sopenharmony_ci ret2 = dqopt->ops[dquot->dq_id.type]->write_file_info( 4788c2ecf20Sopenharmony_ci dquot->dq_sb, dquot->dq_id.type); 4798c2ecf20Sopenharmony_ci } 4808c2ecf20Sopenharmony_ci if (ret < 0) 4818c2ecf20Sopenharmony_ci goto out_iolock; 4828c2ecf20Sopenharmony_ci if (ret2 < 0) { 4838c2ecf20Sopenharmony_ci ret = ret2; 4848c2ecf20Sopenharmony_ci goto out_iolock; 4858c2ecf20Sopenharmony_ci } 4868c2ecf20Sopenharmony_ci } 4878c2ecf20Sopenharmony_ci /* 4888c2ecf20Sopenharmony_ci * Make sure flags update is visible after on-disk struct has been 4898c2ecf20Sopenharmony_ci * allocated. Paired with smp_rmb() in dqget(). 4908c2ecf20Sopenharmony_ci */ 4918c2ecf20Sopenharmony_ci smp_mb__before_atomic(); 4928c2ecf20Sopenharmony_ci set_bit(DQ_ACTIVE_B, &dquot->dq_flags); 4938c2ecf20Sopenharmony_ciout_iolock: 4948c2ecf20Sopenharmony_ci memalloc_nofs_restore(memalloc); 4958c2ecf20Sopenharmony_ci mutex_unlock(&dquot->dq_lock); 4968c2ecf20Sopenharmony_ci return ret; 4978c2ecf20Sopenharmony_ci} 4988c2ecf20Sopenharmony_ciEXPORT_SYMBOL(dquot_acquire); 4998c2ecf20Sopenharmony_ci 5008c2ecf20Sopenharmony_ci/* 5018c2ecf20Sopenharmony_ci * Write dquot to disk 5028c2ecf20Sopenharmony_ci */ 5038c2ecf20Sopenharmony_ciint dquot_commit(struct dquot *dquot) 5048c2ecf20Sopenharmony_ci{ 5058c2ecf20Sopenharmony_ci int ret = 0; 5068c2ecf20Sopenharmony_ci unsigned int memalloc; 5078c2ecf20Sopenharmony_ci struct quota_info *dqopt = sb_dqopt(dquot->dq_sb); 5088c2ecf20Sopenharmony_ci 5098c2ecf20Sopenharmony_ci mutex_lock(&dquot->dq_lock); 5108c2ecf20Sopenharmony_ci memalloc = memalloc_nofs_save(); 5118c2ecf20Sopenharmony_ci if (!clear_dquot_dirty(dquot)) 5128c2ecf20Sopenharmony_ci goto out_lock; 5138c2ecf20Sopenharmony_ci /* Inactive dquot can be only if there was error during read/init 5148c2ecf20Sopenharmony_ci * => we have better not writing it */ 5158c2ecf20Sopenharmony_ci if (dquot_active(dquot)) 5168c2ecf20Sopenharmony_ci ret = dqopt->ops[dquot->dq_id.type]->commit_dqblk(dquot); 5178c2ecf20Sopenharmony_ci else 5188c2ecf20Sopenharmony_ci ret = -EIO; 5198c2ecf20Sopenharmony_ciout_lock: 5208c2ecf20Sopenharmony_ci memalloc_nofs_restore(memalloc); 5218c2ecf20Sopenharmony_ci mutex_unlock(&dquot->dq_lock); 5228c2ecf20Sopenharmony_ci return ret; 5238c2ecf20Sopenharmony_ci} 5248c2ecf20Sopenharmony_ciEXPORT_SYMBOL(dquot_commit); 5258c2ecf20Sopenharmony_ci 5268c2ecf20Sopenharmony_ci/* 5278c2ecf20Sopenharmony_ci * Release dquot 5288c2ecf20Sopenharmony_ci */ 5298c2ecf20Sopenharmony_ciint dquot_release(struct dquot *dquot) 5308c2ecf20Sopenharmony_ci{ 5318c2ecf20Sopenharmony_ci int ret = 0, ret2 = 0; 5328c2ecf20Sopenharmony_ci unsigned int memalloc; 5338c2ecf20Sopenharmony_ci struct quota_info *dqopt = sb_dqopt(dquot->dq_sb); 5348c2ecf20Sopenharmony_ci 5358c2ecf20Sopenharmony_ci mutex_lock(&dquot->dq_lock); 5368c2ecf20Sopenharmony_ci memalloc = memalloc_nofs_save(); 5378c2ecf20Sopenharmony_ci /* Check whether we are not racing with some other dqget() */ 5388c2ecf20Sopenharmony_ci if (dquot_is_busy(dquot)) 5398c2ecf20Sopenharmony_ci goto out_dqlock; 5408c2ecf20Sopenharmony_ci if (dqopt->ops[dquot->dq_id.type]->release_dqblk) { 5418c2ecf20Sopenharmony_ci ret = dqopt->ops[dquot->dq_id.type]->release_dqblk(dquot); 5428c2ecf20Sopenharmony_ci /* Write the info */ 5438c2ecf20Sopenharmony_ci if (info_dirty(&dqopt->info[dquot->dq_id.type])) { 5448c2ecf20Sopenharmony_ci ret2 = dqopt->ops[dquot->dq_id.type]->write_file_info( 5458c2ecf20Sopenharmony_ci dquot->dq_sb, dquot->dq_id.type); 5468c2ecf20Sopenharmony_ci } 5478c2ecf20Sopenharmony_ci if (ret >= 0) 5488c2ecf20Sopenharmony_ci ret = ret2; 5498c2ecf20Sopenharmony_ci } 5508c2ecf20Sopenharmony_ci clear_bit(DQ_ACTIVE_B, &dquot->dq_flags); 5518c2ecf20Sopenharmony_ciout_dqlock: 5528c2ecf20Sopenharmony_ci memalloc_nofs_restore(memalloc); 5538c2ecf20Sopenharmony_ci mutex_unlock(&dquot->dq_lock); 5548c2ecf20Sopenharmony_ci return ret; 5558c2ecf20Sopenharmony_ci} 5568c2ecf20Sopenharmony_ciEXPORT_SYMBOL(dquot_release); 5578c2ecf20Sopenharmony_ci 5588c2ecf20Sopenharmony_civoid dquot_destroy(struct dquot *dquot) 5598c2ecf20Sopenharmony_ci{ 5608c2ecf20Sopenharmony_ci kmem_cache_free(dquot_cachep, dquot); 5618c2ecf20Sopenharmony_ci} 5628c2ecf20Sopenharmony_ciEXPORT_SYMBOL(dquot_destroy); 5638c2ecf20Sopenharmony_ci 5648c2ecf20Sopenharmony_cistatic inline void do_destroy_dquot(struct dquot *dquot) 5658c2ecf20Sopenharmony_ci{ 5668c2ecf20Sopenharmony_ci dquot->dq_sb->dq_op->destroy_dquot(dquot); 5678c2ecf20Sopenharmony_ci} 5688c2ecf20Sopenharmony_ci 5698c2ecf20Sopenharmony_ci/* Invalidate all dquots on the list. Note that this function is called after 5708c2ecf20Sopenharmony_ci * quota is disabled and pointers from inodes removed so there cannot be new 5718c2ecf20Sopenharmony_ci * quota users. There can still be some users of quotas due to inodes being 5728c2ecf20Sopenharmony_ci * just deleted or pruned by prune_icache() (those are not attached to any 5738c2ecf20Sopenharmony_ci * list) or parallel quotactl call. We have to wait for such users. 5748c2ecf20Sopenharmony_ci */ 5758c2ecf20Sopenharmony_cistatic void invalidate_dquots(struct super_block *sb, int type) 5768c2ecf20Sopenharmony_ci{ 5778c2ecf20Sopenharmony_ci struct dquot *dquot, *tmp; 5788c2ecf20Sopenharmony_ci 5798c2ecf20Sopenharmony_cirestart: 5808c2ecf20Sopenharmony_ci flush_delayed_work("a_release_work); 5818c2ecf20Sopenharmony_ci 5828c2ecf20Sopenharmony_ci spin_lock(&dq_list_lock); 5838c2ecf20Sopenharmony_ci list_for_each_entry_safe(dquot, tmp, &inuse_list, dq_inuse) { 5848c2ecf20Sopenharmony_ci if (dquot->dq_sb != sb) 5858c2ecf20Sopenharmony_ci continue; 5868c2ecf20Sopenharmony_ci if (dquot->dq_id.type != type) 5878c2ecf20Sopenharmony_ci continue; 5888c2ecf20Sopenharmony_ci /* Wait for dquot users */ 5898c2ecf20Sopenharmony_ci if (atomic_read(&dquot->dq_count)) { 5908c2ecf20Sopenharmony_ci atomic_inc(&dquot->dq_count); 5918c2ecf20Sopenharmony_ci spin_unlock(&dq_list_lock); 5928c2ecf20Sopenharmony_ci /* 5938c2ecf20Sopenharmony_ci * Once dqput() wakes us up, we know it's time to free 5948c2ecf20Sopenharmony_ci * the dquot. 5958c2ecf20Sopenharmony_ci * IMPORTANT: we rely on the fact that there is always 5968c2ecf20Sopenharmony_ci * at most one process waiting for dquot to free. 5978c2ecf20Sopenharmony_ci * Otherwise dq_count would be > 1 and we would never 5988c2ecf20Sopenharmony_ci * wake up. 5998c2ecf20Sopenharmony_ci */ 6008c2ecf20Sopenharmony_ci wait_event(dquot_ref_wq, 6018c2ecf20Sopenharmony_ci atomic_read(&dquot->dq_count) == 1); 6028c2ecf20Sopenharmony_ci dqput(dquot); 6038c2ecf20Sopenharmony_ci /* At this moment dquot() need not exist (it could be 6048c2ecf20Sopenharmony_ci * reclaimed by prune_dqcache(). Hence we must 6058c2ecf20Sopenharmony_ci * restart. */ 6068c2ecf20Sopenharmony_ci goto restart; 6078c2ecf20Sopenharmony_ci } 6088c2ecf20Sopenharmony_ci /* 6098c2ecf20Sopenharmony_ci * The last user already dropped its reference but dquot didn't 6108c2ecf20Sopenharmony_ci * get fully cleaned up yet. Restart the scan which flushes the 6118c2ecf20Sopenharmony_ci * work cleaning up released dquots. 6128c2ecf20Sopenharmony_ci */ 6138c2ecf20Sopenharmony_ci if (test_bit(DQ_RELEASING_B, &dquot->dq_flags)) { 6148c2ecf20Sopenharmony_ci spin_unlock(&dq_list_lock); 6158c2ecf20Sopenharmony_ci goto restart; 6168c2ecf20Sopenharmony_ci } 6178c2ecf20Sopenharmony_ci /* 6188c2ecf20Sopenharmony_ci * Quota now has no users and it has been written on last 6198c2ecf20Sopenharmony_ci * dqput() 6208c2ecf20Sopenharmony_ci */ 6218c2ecf20Sopenharmony_ci remove_dquot_hash(dquot); 6228c2ecf20Sopenharmony_ci remove_free_dquot(dquot); 6238c2ecf20Sopenharmony_ci remove_inuse(dquot); 6248c2ecf20Sopenharmony_ci do_destroy_dquot(dquot); 6258c2ecf20Sopenharmony_ci } 6268c2ecf20Sopenharmony_ci spin_unlock(&dq_list_lock); 6278c2ecf20Sopenharmony_ci} 6288c2ecf20Sopenharmony_ci 6298c2ecf20Sopenharmony_ci/* Call callback for every active dquot on given filesystem */ 6308c2ecf20Sopenharmony_ciint dquot_scan_active(struct super_block *sb, 6318c2ecf20Sopenharmony_ci int (*fn)(struct dquot *dquot, unsigned long priv), 6328c2ecf20Sopenharmony_ci unsigned long priv) 6338c2ecf20Sopenharmony_ci{ 6348c2ecf20Sopenharmony_ci struct dquot *dquot, *old_dquot = NULL; 6358c2ecf20Sopenharmony_ci int ret = 0; 6368c2ecf20Sopenharmony_ci 6378c2ecf20Sopenharmony_ci WARN_ON_ONCE(!rwsem_is_locked(&sb->s_umount)); 6388c2ecf20Sopenharmony_ci 6398c2ecf20Sopenharmony_ci spin_lock(&dq_list_lock); 6408c2ecf20Sopenharmony_ci list_for_each_entry(dquot, &inuse_list, dq_inuse) { 6418c2ecf20Sopenharmony_ci if (!dquot_active(dquot)) 6428c2ecf20Sopenharmony_ci continue; 6438c2ecf20Sopenharmony_ci if (dquot->dq_sb != sb) 6448c2ecf20Sopenharmony_ci continue; 6458c2ecf20Sopenharmony_ci /* Now we have active dquot so we can just increase use count */ 6468c2ecf20Sopenharmony_ci atomic_inc(&dquot->dq_count); 6478c2ecf20Sopenharmony_ci spin_unlock(&dq_list_lock); 6488c2ecf20Sopenharmony_ci dqput(old_dquot); 6498c2ecf20Sopenharmony_ci old_dquot = dquot; 6508c2ecf20Sopenharmony_ci /* 6518c2ecf20Sopenharmony_ci * ->release_dquot() can be racing with us. Our reference 6528c2ecf20Sopenharmony_ci * protects us from new calls to it so just wait for any 6538c2ecf20Sopenharmony_ci * outstanding call and recheck the DQ_ACTIVE_B after that. 6548c2ecf20Sopenharmony_ci */ 6558c2ecf20Sopenharmony_ci wait_on_dquot(dquot); 6568c2ecf20Sopenharmony_ci if (dquot_active(dquot)) { 6578c2ecf20Sopenharmony_ci ret = fn(dquot, priv); 6588c2ecf20Sopenharmony_ci if (ret < 0) 6598c2ecf20Sopenharmony_ci goto out; 6608c2ecf20Sopenharmony_ci } 6618c2ecf20Sopenharmony_ci spin_lock(&dq_list_lock); 6628c2ecf20Sopenharmony_ci /* We are safe to continue now because our dquot could not 6638c2ecf20Sopenharmony_ci * be moved out of the inuse list while we hold the reference */ 6648c2ecf20Sopenharmony_ci } 6658c2ecf20Sopenharmony_ci spin_unlock(&dq_list_lock); 6668c2ecf20Sopenharmony_ciout: 6678c2ecf20Sopenharmony_ci dqput(old_dquot); 6688c2ecf20Sopenharmony_ci return ret; 6698c2ecf20Sopenharmony_ci} 6708c2ecf20Sopenharmony_ciEXPORT_SYMBOL(dquot_scan_active); 6718c2ecf20Sopenharmony_ci 6728c2ecf20Sopenharmony_cistatic inline int dquot_write_dquot(struct dquot *dquot) 6738c2ecf20Sopenharmony_ci{ 6748c2ecf20Sopenharmony_ci int ret = dquot->dq_sb->dq_op->write_dquot(dquot); 6758c2ecf20Sopenharmony_ci if (ret < 0) { 6768c2ecf20Sopenharmony_ci quota_error(dquot->dq_sb, "Can't write quota structure " 6778c2ecf20Sopenharmony_ci "(error %d). Quota may get out of sync!", ret); 6788c2ecf20Sopenharmony_ci /* Clear dirty bit anyway to avoid infinite loop. */ 6798c2ecf20Sopenharmony_ci clear_dquot_dirty(dquot); 6808c2ecf20Sopenharmony_ci } 6818c2ecf20Sopenharmony_ci return ret; 6828c2ecf20Sopenharmony_ci} 6838c2ecf20Sopenharmony_ci 6848c2ecf20Sopenharmony_ci/* Write all dquot structures to quota files */ 6858c2ecf20Sopenharmony_ciint dquot_writeback_dquots(struct super_block *sb, int type) 6868c2ecf20Sopenharmony_ci{ 6878c2ecf20Sopenharmony_ci struct list_head dirty; 6888c2ecf20Sopenharmony_ci struct dquot *dquot; 6898c2ecf20Sopenharmony_ci struct quota_info *dqopt = sb_dqopt(sb); 6908c2ecf20Sopenharmony_ci int cnt; 6918c2ecf20Sopenharmony_ci int err, ret = 0; 6928c2ecf20Sopenharmony_ci 6938c2ecf20Sopenharmony_ci WARN_ON_ONCE(!rwsem_is_locked(&sb->s_umount)); 6948c2ecf20Sopenharmony_ci 6958c2ecf20Sopenharmony_ci for (cnt = 0; cnt < MAXQUOTAS; cnt++) { 6968c2ecf20Sopenharmony_ci if (type != -1 && cnt != type) 6978c2ecf20Sopenharmony_ci continue; 6988c2ecf20Sopenharmony_ci if (!sb_has_quota_active(sb, cnt)) 6998c2ecf20Sopenharmony_ci continue; 7008c2ecf20Sopenharmony_ci spin_lock(&dq_list_lock); 7018c2ecf20Sopenharmony_ci /* Move list away to avoid livelock. */ 7028c2ecf20Sopenharmony_ci list_replace_init(&dqopt->info[cnt].dqi_dirty_list, &dirty); 7038c2ecf20Sopenharmony_ci while (!list_empty(&dirty)) { 7048c2ecf20Sopenharmony_ci dquot = list_first_entry(&dirty, struct dquot, 7058c2ecf20Sopenharmony_ci dq_dirty); 7068c2ecf20Sopenharmony_ci 7078c2ecf20Sopenharmony_ci WARN_ON(!dquot_active(dquot)); 7088c2ecf20Sopenharmony_ci /* If the dquot is releasing we should not touch it */ 7098c2ecf20Sopenharmony_ci if (test_bit(DQ_RELEASING_B, &dquot->dq_flags)) { 7108c2ecf20Sopenharmony_ci spin_unlock(&dq_list_lock); 7118c2ecf20Sopenharmony_ci flush_delayed_work("a_release_work); 7128c2ecf20Sopenharmony_ci spin_lock(&dq_list_lock); 7138c2ecf20Sopenharmony_ci continue; 7148c2ecf20Sopenharmony_ci } 7158c2ecf20Sopenharmony_ci 7168c2ecf20Sopenharmony_ci /* Now we have active dquot from which someone is 7178c2ecf20Sopenharmony_ci * holding reference so we can safely just increase 7188c2ecf20Sopenharmony_ci * use count */ 7198c2ecf20Sopenharmony_ci dqgrab(dquot); 7208c2ecf20Sopenharmony_ci spin_unlock(&dq_list_lock); 7218c2ecf20Sopenharmony_ci err = dquot_write_dquot(dquot); 7228c2ecf20Sopenharmony_ci if (err && !ret) 7238c2ecf20Sopenharmony_ci ret = err; 7248c2ecf20Sopenharmony_ci dqput(dquot); 7258c2ecf20Sopenharmony_ci spin_lock(&dq_list_lock); 7268c2ecf20Sopenharmony_ci } 7278c2ecf20Sopenharmony_ci spin_unlock(&dq_list_lock); 7288c2ecf20Sopenharmony_ci } 7298c2ecf20Sopenharmony_ci 7308c2ecf20Sopenharmony_ci for (cnt = 0; cnt < MAXQUOTAS; cnt++) 7318c2ecf20Sopenharmony_ci if ((cnt == type || type == -1) && sb_has_quota_active(sb, cnt) 7328c2ecf20Sopenharmony_ci && info_dirty(&dqopt->info[cnt])) 7338c2ecf20Sopenharmony_ci sb->dq_op->write_info(sb, cnt); 7348c2ecf20Sopenharmony_ci dqstats_inc(DQST_SYNCS); 7358c2ecf20Sopenharmony_ci 7368c2ecf20Sopenharmony_ci return ret; 7378c2ecf20Sopenharmony_ci} 7388c2ecf20Sopenharmony_ciEXPORT_SYMBOL(dquot_writeback_dquots); 7398c2ecf20Sopenharmony_ci 7408c2ecf20Sopenharmony_ci/* Write all dquot structures to disk and make them visible from userspace */ 7418c2ecf20Sopenharmony_ciint dquot_quota_sync(struct super_block *sb, int type) 7428c2ecf20Sopenharmony_ci{ 7438c2ecf20Sopenharmony_ci struct quota_info *dqopt = sb_dqopt(sb); 7448c2ecf20Sopenharmony_ci int cnt; 7458c2ecf20Sopenharmony_ci int ret; 7468c2ecf20Sopenharmony_ci 7478c2ecf20Sopenharmony_ci ret = dquot_writeback_dquots(sb, type); 7488c2ecf20Sopenharmony_ci if (ret) 7498c2ecf20Sopenharmony_ci return ret; 7508c2ecf20Sopenharmony_ci if (dqopt->flags & DQUOT_QUOTA_SYS_FILE) 7518c2ecf20Sopenharmony_ci return 0; 7528c2ecf20Sopenharmony_ci 7538c2ecf20Sopenharmony_ci /* This is not very clever (and fast) but currently I don't know about 7548c2ecf20Sopenharmony_ci * any other simple way of getting quota data to disk and we must get 7558c2ecf20Sopenharmony_ci * them there for userspace to be visible... */ 7568c2ecf20Sopenharmony_ci if (sb->s_op->sync_fs) { 7578c2ecf20Sopenharmony_ci ret = sb->s_op->sync_fs(sb, 1); 7588c2ecf20Sopenharmony_ci if (ret) 7598c2ecf20Sopenharmony_ci return ret; 7608c2ecf20Sopenharmony_ci } 7618c2ecf20Sopenharmony_ci ret = sync_blockdev(sb->s_bdev); 7628c2ecf20Sopenharmony_ci if (ret) 7638c2ecf20Sopenharmony_ci return ret; 7648c2ecf20Sopenharmony_ci 7658c2ecf20Sopenharmony_ci /* 7668c2ecf20Sopenharmony_ci * Now when everything is written we can discard the pagecache so 7678c2ecf20Sopenharmony_ci * that userspace sees the changes. 7688c2ecf20Sopenharmony_ci */ 7698c2ecf20Sopenharmony_ci for (cnt = 0; cnt < MAXQUOTAS; cnt++) { 7708c2ecf20Sopenharmony_ci if (type != -1 && cnt != type) 7718c2ecf20Sopenharmony_ci continue; 7728c2ecf20Sopenharmony_ci if (!sb_has_quota_active(sb, cnt)) 7738c2ecf20Sopenharmony_ci continue; 7748c2ecf20Sopenharmony_ci inode_lock(dqopt->files[cnt]); 7758c2ecf20Sopenharmony_ci truncate_inode_pages(&dqopt->files[cnt]->i_data, 0); 7768c2ecf20Sopenharmony_ci inode_unlock(dqopt->files[cnt]); 7778c2ecf20Sopenharmony_ci } 7788c2ecf20Sopenharmony_ci 7798c2ecf20Sopenharmony_ci return 0; 7808c2ecf20Sopenharmony_ci} 7818c2ecf20Sopenharmony_ciEXPORT_SYMBOL(dquot_quota_sync); 7828c2ecf20Sopenharmony_ci 7838c2ecf20Sopenharmony_cistatic unsigned long 7848c2ecf20Sopenharmony_cidqcache_shrink_scan(struct shrinker *shrink, struct shrink_control *sc) 7858c2ecf20Sopenharmony_ci{ 7868c2ecf20Sopenharmony_ci struct dquot *dquot; 7878c2ecf20Sopenharmony_ci unsigned long freed = 0; 7888c2ecf20Sopenharmony_ci 7898c2ecf20Sopenharmony_ci spin_lock(&dq_list_lock); 7908c2ecf20Sopenharmony_ci while (!list_empty(&free_dquots) && sc->nr_to_scan) { 7918c2ecf20Sopenharmony_ci dquot = list_first_entry(&free_dquots, struct dquot, dq_free); 7928c2ecf20Sopenharmony_ci remove_dquot_hash(dquot); 7938c2ecf20Sopenharmony_ci remove_free_dquot(dquot); 7948c2ecf20Sopenharmony_ci remove_inuse(dquot); 7958c2ecf20Sopenharmony_ci do_destroy_dquot(dquot); 7968c2ecf20Sopenharmony_ci sc->nr_to_scan--; 7978c2ecf20Sopenharmony_ci freed++; 7988c2ecf20Sopenharmony_ci } 7998c2ecf20Sopenharmony_ci spin_unlock(&dq_list_lock); 8008c2ecf20Sopenharmony_ci return freed; 8018c2ecf20Sopenharmony_ci} 8028c2ecf20Sopenharmony_ci 8038c2ecf20Sopenharmony_cistatic unsigned long 8048c2ecf20Sopenharmony_cidqcache_shrink_count(struct shrinker *shrink, struct shrink_control *sc) 8058c2ecf20Sopenharmony_ci{ 8068c2ecf20Sopenharmony_ci return vfs_pressure_ratio( 8078c2ecf20Sopenharmony_ci percpu_counter_read_positive(&dqstats.counter[DQST_FREE_DQUOTS])); 8088c2ecf20Sopenharmony_ci} 8098c2ecf20Sopenharmony_ci 8108c2ecf20Sopenharmony_cistatic struct shrinker dqcache_shrinker = { 8118c2ecf20Sopenharmony_ci .count_objects = dqcache_shrink_count, 8128c2ecf20Sopenharmony_ci .scan_objects = dqcache_shrink_scan, 8138c2ecf20Sopenharmony_ci .seeks = DEFAULT_SEEKS, 8148c2ecf20Sopenharmony_ci}; 8158c2ecf20Sopenharmony_ci 8168c2ecf20Sopenharmony_ci/* 8178c2ecf20Sopenharmony_ci * Safely release dquot and put reference to dquot. 8188c2ecf20Sopenharmony_ci */ 8198c2ecf20Sopenharmony_cistatic void quota_release_workfn(struct work_struct *work) 8208c2ecf20Sopenharmony_ci{ 8218c2ecf20Sopenharmony_ci struct dquot *dquot; 8228c2ecf20Sopenharmony_ci struct list_head rls_head; 8238c2ecf20Sopenharmony_ci 8248c2ecf20Sopenharmony_ci spin_lock(&dq_list_lock); 8258c2ecf20Sopenharmony_ci /* Exchange the list head to avoid livelock. */ 8268c2ecf20Sopenharmony_ci list_replace_init(&releasing_dquots, &rls_head); 8278c2ecf20Sopenharmony_ci spin_unlock(&dq_list_lock); 8288c2ecf20Sopenharmony_ci synchronize_srcu(&dquot_srcu); 8298c2ecf20Sopenharmony_ci 8308c2ecf20Sopenharmony_cirestart: 8318c2ecf20Sopenharmony_ci spin_lock(&dq_list_lock); 8328c2ecf20Sopenharmony_ci while (!list_empty(&rls_head)) { 8338c2ecf20Sopenharmony_ci dquot = list_first_entry(&rls_head, struct dquot, dq_free); 8348c2ecf20Sopenharmony_ci WARN_ON_ONCE(atomic_read(&dquot->dq_count)); 8358c2ecf20Sopenharmony_ci /* 8368c2ecf20Sopenharmony_ci * Note that DQ_RELEASING_B protects us from racing with 8378c2ecf20Sopenharmony_ci * invalidate_dquots() calls so we are safe to work with the 8388c2ecf20Sopenharmony_ci * dquot even after we drop dq_list_lock. 8398c2ecf20Sopenharmony_ci */ 8408c2ecf20Sopenharmony_ci if (dquot_dirty(dquot)) { 8418c2ecf20Sopenharmony_ci spin_unlock(&dq_list_lock); 8428c2ecf20Sopenharmony_ci /* Commit dquot before releasing */ 8438c2ecf20Sopenharmony_ci dquot_write_dquot(dquot); 8448c2ecf20Sopenharmony_ci goto restart; 8458c2ecf20Sopenharmony_ci } 8468c2ecf20Sopenharmony_ci if (dquot_active(dquot)) { 8478c2ecf20Sopenharmony_ci spin_unlock(&dq_list_lock); 8488c2ecf20Sopenharmony_ci dquot->dq_sb->dq_op->release_dquot(dquot); 8498c2ecf20Sopenharmony_ci goto restart; 8508c2ecf20Sopenharmony_ci } 8518c2ecf20Sopenharmony_ci /* Dquot is inactive and clean, now move it to free list */ 8528c2ecf20Sopenharmony_ci remove_free_dquot(dquot); 8538c2ecf20Sopenharmony_ci put_dquot_last(dquot); 8548c2ecf20Sopenharmony_ci } 8558c2ecf20Sopenharmony_ci spin_unlock(&dq_list_lock); 8568c2ecf20Sopenharmony_ci} 8578c2ecf20Sopenharmony_ci 8588c2ecf20Sopenharmony_ci/* 8598c2ecf20Sopenharmony_ci * Put reference to dquot 8608c2ecf20Sopenharmony_ci */ 8618c2ecf20Sopenharmony_civoid dqput(struct dquot *dquot) 8628c2ecf20Sopenharmony_ci{ 8638c2ecf20Sopenharmony_ci if (!dquot) 8648c2ecf20Sopenharmony_ci return; 8658c2ecf20Sopenharmony_ci#ifdef CONFIG_QUOTA_DEBUG 8668c2ecf20Sopenharmony_ci if (!atomic_read(&dquot->dq_count)) { 8678c2ecf20Sopenharmony_ci quota_error(dquot->dq_sb, "trying to free free dquot of %s %d", 8688c2ecf20Sopenharmony_ci quotatypes[dquot->dq_id.type], 8698c2ecf20Sopenharmony_ci from_kqid(&init_user_ns, dquot->dq_id)); 8708c2ecf20Sopenharmony_ci BUG(); 8718c2ecf20Sopenharmony_ci } 8728c2ecf20Sopenharmony_ci#endif 8738c2ecf20Sopenharmony_ci dqstats_inc(DQST_DROPS); 8748c2ecf20Sopenharmony_ci 8758c2ecf20Sopenharmony_ci spin_lock(&dq_list_lock); 8768c2ecf20Sopenharmony_ci if (atomic_read(&dquot->dq_count) > 1) { 8778c2ecf20Sopenharmony_ci /* We have more than one user... nothing to do */ 8788c2ecf20Sopenharmony_ci atomic_dec(&dquot->dq_count); 8798c2ecf20Sopenharmony_ci /* Releasing dquot during quotaoff phase? */ 8808c2ecf20Sopenharmony_ci if (!sb_has_quota_active(dquot->dq_sb, dquot->dq_id.type) && 8818c2ecf20Sopenharmony_ci atomic_read(&dquot->dq_count) == 1) 8828c2ecf20Sopenharmony_ci wake_up(&dquot_ref_wq); 8838c2ecf20Sopenharmony_ci spin_unlock(&dq_list_lock); 8848c2ecf20Sopenharmony_ci return; 8858c2ecf20Sopenharmony_ci } 8868c2ecf20Sopenharmony_ci 8878c2ecf20Sopenharmony_ci /* Need to release dquot? */ 8888c2ecf20Sopenharmony_ci#ifdef CONFIG_QUOTA_DEBUG 8898c2ecf20Sopenharmony_ci /* sanity check */ 8908c2ecf20Sopenharmony_ci BUG_ON(!list_empty(&dquot->dq_free)); 8918c2ecf20Sopenharmony_ci#endif 8928c2ecf20Sopenharmony_ci put_releasing_dquots(dquot); 8938c2ecf20Sopenharmony_ci atomic_dec(&dquot->dq_count); 8948c2ecf20Sopenharmony_ci spin_unlock(&dq_list_lock); 8958c2ecf20Sopenharmony_ci queue_delayed_work(system_unbound_wq, "a_release_work, 1); 8968c2ecf20Sopenharmony_ci} 8978c2ecf20Sopenharmony_ciEXPORT_SYMBOL(dqput); 8988c2ecf20Sopenharmony_ci 8998c2ecf20Sopenharmony_cistruct dquot *dquot_alloc(struct super_block *sb, int type) 9008c2ecf20Sopenharmony_ci{ 9018c2ecf20Sopenharmony_ci return kmem_cache_zalloc(dquot_cachep, GFP_NOFS); 9028c2ecf20Sopenharmony_ci} 9038c2ecf20Sopenharmony_ciEXPORT_SYMBOL(dquot_alloc); 9048c2ecf20Sopenharmony_ci 9058c2ecf20Sopenharmony_cistatic struct dquot *get_empty_dquot(struct super_block *sb, int type) 9068c2ecf20Sopenharmony_ci{ 9078c2ecf20Sopenharmony_ci struct dquot *dquot; 9088c2ecf20Sopenharmony_ci 9098c2ecf20Sopenharmony_ci dquot = sb->dq_op->alloc_dquot(sb, type); 9108c2ecf20Sopenharmony_ci if(!dquot) 9118c2ecf20Sopenharmony_ci return NULL; 9128c2ecf20Sopenharmony_ci 9138c2ecf20Sopenharmony_ci mutex_init(&dquot->dq_lock); 9148c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&dquot->dq_free); 9158c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&dquot->dq_inuse); 9168c2ecf20Sopenharmony_ci INIT_HLIST_NODE(&dquot->dq_hash); 9178c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&dquot->dq_dirty); 9188c2ecf20Sopenharmony_ci dquot->dq_sb = sb; 9198c2ecf20Sopenharmony_ci dquot->dq_id = make_kqid_invalid(type); 9208c2ecf20Sopenharmony_ci atomic_set(&dquot->dq_count, 1); 9218c2ecf20Sopenharmony_ci spin_lock_init(&dquot->dq_dqb_lock); 9228c2ecf20Sopenharmony_ci 9238c2ecf20Sopenharmony_ci return dquot; 9248c2ecf20Sopenharmony_ci} 9258c2ecf20Sopenharmony_ci 9268c2ecf20Sopenharmony_ci/* 9278c2ecf20Sopenharmony_ci * Get reference to dquot 9288c2ecf20Sopenharmony_ci * 9298c2ecf20Sopenharmony_ci * Locking is slightly tricky here. We are guarded from parallel quotaoff() 9308c2ecf20Sopenharmony_ci * destroying our dquot by: 9318c2ecf20Sopenharmony_ci * a) checking for quota flags under dq_list_lock and 9328c2ecf20Sopenharmony_ci * b) getting a reference to dquot before we release dq_list_lock 9338c2ecf20Sopenharmony_ci */ 9348c2ecf20Sopenharmony_cistruct dquot *dqget(struct super_block *sb, struct kqid qid) 9358c2ecf20Sopenharmony_ci{ 9368c2ecf20Sopenharmony_ci unsigned int hashent = hashfn(sb, qid); 9378c2ecf20Sopenharmony_ci struct dquot *dquot, *empty = NULL; 9388c2ecf20Sopenharmony_ci 9398c2ecf20Sopenharmony_ci if (!qid_has_mapping(sb->s_user_ns, qid)) 9408c2ecf20Sopenharmony_ci return ERR_PTR(-EINVAL); 9418c2ecf20Sopenharmony_ci 9428c2ecf20Sopenharmony_ci if (!sb_has_quota_active(sb, qid.type)) 9438c2ecf20Sopenharmony_ci return ERR_PTR(-ESRCH); 9448c2ecf20Sopenharmony_ciwe_slept: 9458c2ecf20Sopenharmony_ci spin_lock(&dq_list_lock); 9468c2ecf20Sopenharmony_ci spin_lock(&dq_state_lock); 9478c2ecf20Sopenharmony_ci if (!sb_has_quota_active(sb, qid.type)) { 9488c2ecf20Sopenharmony_ci spin_unlock(&dq_state_lock); 9498c2ecf20Sopenharmony_ci spin_unlock(&dq_list_lock); 9508c2ecf20Sopenharmony_ci dquot = ERR_PTR(-ESRCH); 9518c2ecf20Sopenharmony_ci goto out; 9528c2ecf20Sopenharmony_ci } 9538c2ecf20Sopenharmony_ci spin_unlock(&dq_state_lock); 9548c2ecf20Sopenharmony_ci 9558c2ecf20Sopenharmony_ci dquot = find_dquot(hashent, sb, qid); 9568c2ecf20Sopenharmony_ci if (!dquot) { 9578c2ecf20Sopenharmony_ci if (!empty) { 9588c2ecf20Sopenharmony_ci spin_unlock(&dq_list_lock); 9598c2ecf20Sopenharmony_ci empty = get_empty_dquot(sb, qid.type); 9608c2ecf20Sopenharmony_ci if (!empty) 9618c2ecf20Sopenharmony_ci schedule(); /* Try to wait for a moment... */ 9628c2ecf20Sopenharmony_ci goto we_slept; 9638c2ecf20Sopenharmony_ci } 9648c2ecf20Sopenharmony_ci dquot = empty; 9658c2ecf20Sopenharmony_ci empty = NULL; 9668c2ecf20Sopenharmony_ci dquot->dq_id = qid; 9678c2ecf20Sopenharmony_ci /* all dquots go on the inuse_list */ 9688c2ecf20Sopenharmony_ci put_inuse(dquot); 9698c2ecf20Sopenharmony_ci /* hash it first so it can be found */ 9708c2ecf20Sopenharmony_ci insert_dquot_hash(dquot); 9718c2ecf20Sopenharmony_ci spin_unlock(&dq_list_lock); 9728c2ecf20Sopenharmony_ci dqstats_inc(DQST_LOOKUPS); 9738c2ecf20Sopenharmony_ci } else { 9748c2ecf20Sopenharmony_ci if (!atomic_read(&dquot->dq_count)) 9758c2ecf20Sopenharmony_ci remove_free_dquot(dquot); 9768c2ecf20Sopenharmony_ci atomic_inc(&dquot->dq_count); 9778c2ecf20Sopenharmony_ci spin_unlock(&dq_list_lock); 9788c2ecf20Sopenharmony_ci dqstats_inc(DQST_CACHE_HITS); 9798c2ecf20Sopenharmony_ci dqstats_inc(DQST_LOOKUPS); 9808c2ecf20Sopenharmony_ci } 9818c2ecf20Sopenharmony_ci /* Wait for dq_lock - after this we know that either dquot_release() is 9828c2ecf20Sopenharmony_ci * already finished or it will be canceled due to dq_count > 0 test */ 9838c2ecf20Sopenharmony_ci wait_on_dquot(dquot); 9848c2ecf20Sopenharmony_ci /* Read the dquot / allocate space in quota file */ 9858c2ecf20Sopenharmony_ci if (!dquot_active(dquot)) { 9868c2ecf20Sopenharmony_ci int err; 9878c2ecf20Sopenharmony_ci 9888c2ecf20Sopenharmony_ci err = sb->dq_op->acquire_dquot(dquot); 9898c2ecf20Sopenharmony_ci if (err < 0) { 9908c2ecf20Sopenharmony_ci dqput(dquot); 9918c2ecf20Sopenharmony_ci dquot = ERR_PTR(err); 9928c2ecf20Sopenharmony_ci goto out; 9938c2ecf20Sopenharmony_ci } 9948c2ecf20Sopenharmony_ci } 9958c2ecf20Sopenharmony_ci /* 9968c2ecf20Sopenharmony_ci * Make sure following reads see filled structure - paired with 9978c2ecf20Sopenharmony_ci * smp_mb__before_atomic() in dquot_acquire(). 9988c2ecf20Sopenharmony_ci */ 9998c2ecf20Sopenharmony_ci smp_rmb(); 10008c2ecf20Sopenharmony_ci#ifdef CONFIG_QUOTA_DEBUG 10018c2ecf20Sopenharmony_ci BUG_ON(!dquot->dq_sb); /* Has somebody invalidated entry under us? */ 10028c2ecf20Sopenharmony_ci#endif 10038c2ecf20Sopenharmony_ciout: 10048c2ecf20Sopenharmony_ci if (empty) 10058c2ecf20Sopenharmony_ci do_destroy_dquot(empty); 10068c2ecf20Sopenharmony_ci 10078c2ecf20Sopenharmony_ci return dquot; 10088c2ecf20Sopenharmony_ci} 10098c2ecf20Sopenharmony_ciEXPORT_SYMBOL(dqget); 10108c2ecf20Sopenharmony_ci 10118c2ecf20Sopenharmony_cistatic inline struct dquot **i_dquot(struct inode *inode) 10128c2ecf20Sopenharmony_ci{ 10138c2ecf20Sopenharmony_ci return inode->i_sb->s_op->get_dquots(inode); 10148c2ecf20Sopenharmony_ci} 10158c2ecf20Sopenharmony_ci 10168c2ecf20Sopenharmony_cistatic int dqinit_needed(struct inode *inode, int type) 10178c2ecf20Sopenharmony_ci{ 10188c2ecf20Sopenharmony_ci struct dquot * const *dquots; 10198c2ecf20Sopenharmony_ci int cnt; 10208c2ecf20Sopenharmony_ci 10218c2ecf20Sopenharmony_ci if (IS_NOQUOTA(inode)) 10228c2ecf20Sopenharmony_ci return 0; 10238c2ecf20Sopenharmony_ci 10248c2ecf20Sopenharmony_ci dquots = i_dquot(inode); 10258c2ecf20Sopenharmony_ci if (type != -1) 10268c2ecf20Sopenharmony_ci return !dquots[type]; 10278c2ecf20Sopenharmony_ci for (cnt = 0; cnt < MAXQUOTAS; cnt++) 10288c2ecf20Sopenharmony_ci if (!dquots[cnt]) 10298c2ecf20Sopenharmony_ci return 1; 10308c2ecf20Sopenharmony_ci return 0; 10318c2ecf20Sopenharmony_ci} 10328c2ecf20Sopenharmony_ci 10338c2ecf20Sopenharmony_ci/* This routine is guarded by s_umount semaphore */ 10348c2ecf20Sopenharmony_cistatic int add_dquot_ref(struct super_block *sb, int type) 10358c2ecf20Sopenharmony_ci{ 10368c2ecf20Sopenharmony_ci struct inode *inode, *old_inode = NULL; 10378c2ecf20Sopenharmony_ci#ifdef CONFIG_QUOTA_DEBUG 10388c2ecf20Sopenharmony_ci int reserved = 0; 10398c2ecf20Sopenharmony_ci#endif 10408c2ecf20Sopenharmony_ci int err = 0; 10418c2ecf20Sopenharmony_ci 10428c2ecf20Sopenharmony_ci spin_lock(&sb->s_inode_list_lock); 10438c2ecf20Sopenharmony_ci list_for_each_entry(inode, &sb->s_inodes, i_sb_list) { 10448c2ecf20Sopenharmony_ci spin_lock(&inode->i_lock); 10458c2ecf20Sopenharmony_ci if ((inode->i_state & (I_FREEING|I_WILL_FREE|I_NEW)) || 10468c2ecf20Sopenharmony_ci !atomic_read(&inode->i_writecount) || 10478c2ecf20Sopenharmony_ci !dqinit_needed(inode, type)) { 10488c2ecf20Sopenharmony_ci spin_unlock(&inode->i_lock); 10498c2ecf20Sopenharmony_ci continue; 10508c2ecf20Sopenharmony_ci } 10518c2ecf20Sopenharmony_ci __iget(inode); 10528c2ecf20Sopenharmony_ci spin_unlock(&inode->i_lock); 10538c2ecf20Sopenharmony_ci spin_unlock(&sb->s_inode_list_lock); 10548c2ecf20Sopenharmony_ci 10558c2ecf20Sopenharmony_ci#ifdef CONFIG_QUOTA_DEBUG 10568c2ecf20Sopenharmony_ci if (unlikely(inode_get_rsv_space(inode) > 0)) 10578c2ecf20Sopenharmony_ci reserved = 1; 10588c2ecf20Sopenharmony_ci#endif 10598c2ecf20Sopenharmony_ci iput(old_inode); 10608c2ecf20Sopenharmony_ci err = __dquot_initialize(inode, type); 10618c2ecf20Sopenharmony_ci if (err) { 10628c2ecf20Sopenharmony_ci iput(inode); 10638c2ecf20Sopenharmony_ci goto out; 10648c2ecf20Sopenharmony_ci } 10658c2ecf20Sopenharmony_ci 10668c2ecf20Sopenharmony_ci /* 10678c2ecf20Sopenharmony_ci * We hold a reference to 'inode' so it couldn't have been 10688c2ecf20Sopenharmony_ci * removed from s_inodes list while we dropped the 10698c2ecf20Sopenharmony_ci * s_inode_list_lock. We cannot iput the inode now as we can be 10708c2ecf20Sopenharmony_ci * holding the last reference and we cannot iput it under 10718c2ecf20Sopenharmony_ci * s_inode_list_lock. So we keep the reference and iput it 10728c2ecf20Sopenharmony_ci * later. 10738c2ecf20Sopenharmony_ci */ 10748c2ecf20Sopenharmony_ci old_inode = inode; 10758c2ecf20Sopenharmony_ci cond_resched(); 10768c2ecf20Sopenharmony_ci spin_lock(&sb->s_inode_list_lock); 10778c2ecf20Sopenharmony_ci } 10788c2ecf20Sopenharmony_ci spin_unlock(&sb->s_inode_list_lock); 10798c2ecf20Sopenharmony_ci iput(old_inode); 10808c2ecf20Sopenharmony_ciout: 10818c2ecf20Sopenharmony_ci#ifdef CONFIG_QUOTA_DEBUG 10828c2ecf20Sopenharmony_ci if (reserved) { 10838c2ecf20Sopenharmony_ci quota_error(sb, "Writes happened before quota was turned on " 10848c2ecf20Sopenharmony_ci "thus quota information is probably inconsistent. " 10858c2ecf20Sopenharmony_ci "Please run quotacheck(8)"); 10868c2ecf20Sopenharmony_ci } 10878c2ecf20Sopenharmony_ci#endif 10888c2ecf20Sopenharmony_ci return err; 10898c2ecf20Sopenharmony_ci} 10908c2ecf20Sopenharmony_ci 10918c2ecf20Sopenharmony_ci/* 10928c2ecf20Sopenharmony_ci * Remove references to dquots from inode and add dquot to list for freeing 10938c2ecf20Sopenharmony_ci * if we have the last reference to dquot 10948c2ecf20Sopenharmony_ci */ 10958c2ecf20Sopenharmony_cistatic void remove_inode_dquot_ref(struct inode *inode, int type, 10968c2ecf20Sopenharmony_ci struct list_head *tofree_head) 10978c2ecf20Sopenharmony_ci{ 10988c2ecf20Sopenharmony_ci struct dquot **dquots = i_dquot(inode); 10998c2ecf20Sopenharmony_ci struct dquot *dquot = dquots[type]; 11008c2ecf20Sopenharmony_ci 11018c2ecf20Sopenharmony_ci if (!dquot) 11028c2ecf20Sopenharmony_ci return; 11038c2ecf20Sopenharmony_ci 11048c2ecf20Sopenharmony_ci dquots[type] = NULL; 11058c2ecf20Sopenharmony_ci if (list_empty(&dquot->dq_free)) { 11068c2ecf20Sopenharmony_ci /* 11078c2ecf20Sopenharmony_ci * The inode still has reference to dquot so it can't be in the 11088c2ecf20Sopenharmony_ci * free list 11098c2ecf20Sopenharmony_ci */ 11108c2ecf20Sopenharmony_ci spin_lock(&dq_list_lock); 11118c2ecf20Sopenharmony_ci list_add(&dquot->dq_free, tofree_head); 11128c2ecf20Sopenharmony_ci spin_unlock(&dq_list_lock); 11138c2ecf20Sopenharmony_ci } else { 11148c2ecf20Sopenharmony_ci /* 11158c2ecf20Sopenharmony_ci * Dquot is already in a list to put so we won't drop the last 11168c2ecf20Sopenharmony_ci * reference here. 11178c2ecf20Sopenharmony_ci */ 11188c2ecf20Sopenharmony_ci dqput(dquot); 11198c2ecf20Sopenharmony_ci } 11208c2ecf20Sopenharmony_ci} 11218c2ecf20Sopenharmony_ci 11228c2ecf20Sopenharmony_ci/* 11238c2ecf20Sopenharmony_ci * Free list of dquots 11248c2ecf20Sopenharmony_ci * Dquots are removed from inodes and no new references can be got so we are 11258c2ecf20Sopenharmony_ci * the only ones holding reference 11268c2ecf20Sopenharmony_ci */ 11278c2ecf20Sopenharmony_cistatic void put_dquot_list(struct list_head *tofree_head) 11288c2ecf20Sopenharmony_ci{ 11298c2ecf20Sopenharmony_ci struct list_head *act_head; 11308c2ecf20Sopenharmony_ci struct dquot *dquot; 11318c2ecf20Sopenharmony_ci 11328c2ecf20Sopenharmony_ci act_head = tofree_head->next; 11338c2ecf20Sopenharmony_ci while (act_head != tofree_head) { 11348c2ecf20Sopenharmony_ci dquot = list_entry(act_head, struct dquot, dq_free); 11358c2ecf20Sopenharmony_ci act_head = act_head->next; 11368c2ecf20Sopenharmony_ci /* Remove dquot from the list so we won't have problems... */ 11378c2ecf20Sopenharmony_ci list_del_init(&dquot->dq_free); 11388c2ecf20Sopenharmony_ci dqput(dquot); 11398c2ecf20Sopenharmony_ci } 11408c2ecf20Sopenharmony_ci} 11418c2ecf20Sopenharmony_ci 11428c2ecf20Sopenharmony_cistatic void remove_dquot_ref(struct super_block *sb, int type, 11438c2ecf20Sopenharmony_ci struct list_head *tofree_head) 11448c2ecf20Sopenharmony_ci{ 11458c2ecf20Sopenharmony_ci struct inode *inode; 11468c2ecf20Sopenharmony_ci#ifdef CONFIG_QUOTA_DEBUG 11478c2ecf20Sopenharmony_ci int reserved = 0; 11488c2ecf20Sopenharmony_ci#endif 11498c2ecf20Sopenharmony_ci 11508c2ecf20Sopenharmony_ci spin_lock(&sb->s_inode_list_lock); 11518c2ecf20Sopenharmony_ci list_for_each_entry(inode, &sb->s_inodes, i_sb_list) { 11528c2ecf20Sopenharmony_ci /* 11538c2ecf20Sopenharmony_ci * We have to scan also I_NEW inodes because they can already 11548c2ecf20Sopenharmony_ci * have quota pointer initialized. Luckily, we need to touch 11558c2ecf20Sopenharmony_ci * only quota pointers and these have separate locking 11568c2ecf20Sopenharmony_ci * (dq_data_lock). 11578c2ecf20Sopenharmony_ci */ 11588c2ecf20Sopenharmony_ci spin_lock(&dq_data_lock); 11598c2ecf20Sopenharmony_ci if (!IS_NOQUOTA(inode)) { 11608c2ecf20Sopenharmony_ci#ifdef CONFIG_QUOTA_DEBUG 11618c2ecf20Sopenharmony_ci if (unlikely(inode_get_rsv_space(inode) > 0)) 11628c2ecf20Sopenharmony_ci reserved = 1; 11638c2ecf20Sopenharmony_ci#endif 11648c2ecf20Sopenharmony_ci remove_inode_dquot_ref(inode, type, tofree_head); 11658c2ecf20Sopenharmony_ci } 11668c2ecf20Sopenharmony_ci spin_unlock(&dq_data_lock); 11678c2ecf20Sopenharmony_ci } 11688c2ecf20Sopenharmony_ci spin_unlock(&sb->s_inode_list_lock); 11698c2ecf20Sopenharmony_ci#ifdef CONFIG_QUOTA_DEBUG 11708c2ecf20Sopenharmony_ci if (reserved) { 11718c2ecf20Sopenharmony_ci printk(KERN_WARNING "VFS (%s): Writes happened after quota" 11728c2ecf20Sopenharmony_ci " was disabled thus quota information is probably " 11738c2ecf20Sopenharmony_ci "inconsistent. Please run quotacheck(8).\n", sb->s_id); 11748c2ecf20Sopenharmony_ci } 11758c2ecf20Sopenharmony_ci#endif 11768c2ecf20Sopenharmony_ci} 11778c2ecf20Sopenharmony_ci 11788c2ecf20Sopenharmony_ci/* Gather all references from inodes and drop them */ 11798c2ecf20Sopenharmony_cistatic void drop_dquot_ref(struct super_block *sb, int type) 11808c2ecf20Sopenharmony_ci{ 11818c2ecf20Sopenharmony_ci LIST_HEAD(tofree_head); 11828c2ecf20Sopenharmony_ci 11838c2ecf20Sopenharmony_ci if (sb->dq_op) { 11848c2ecf20Sopenharmony_ci remove_dquot_ref(sb, type, &tofree_head); 11858c2ecf20Sopenharmony_ci synchronize_srcu(&dquot_srcu); 11868c2ecf20Sopenharmony_ci put_dquot_list(&tofree_head); 11878c2ecf20Sopenharmony_ci } 11888c2ecf20Sopenharmony_ci} 11898c2ecf20Sopenharmony_ci 11908c2ecf20Sopenharmony_cistatic inline 11918c2ecf20Sopenharmony_civoid dquot_free_reserved_space(struct dquot *dquot, qsize_t number) 11928c2ecf20Sopenharmony_ci{ 11938c2ecf20Sopenharmony_ci if (dquot->dq_dqb.dqb_rsvspace >= number) 11948c2ecf20Sopenharmony_ci dquot->dq_dqb.dqb_rsvspace -= number; 11958c2ecf20Sopenharmony_ci else { 11968c2ecf20Sopenharmony_ci WARN_ON_ONCE(1); 11978c2ecf20Sopenharmony_ci dquot->dq_dqb.dqb_rsvspace = 0; 11988c2ecf20Sopenharmony_ci } 11998c2ecf20Sopenharmony_ci if (dquot->dq_dqb.dqb_curspace + dquot->dq_dqb.dqb_rsvspace <= 12008c2ecf20Sopenharmony_ci dquot->dq_dqb.dqb_bsoftlimit) 12018c2ecf20Sopenharmony_ci dquot->dq_dqb.dqb_btime = (time64_t) 0; 12028c2ecf20Sopenharmony_ci clear_bit(DQ_BLKS_B, &dquot->dq_flags); 12038c2ecf20Sopenharmony_ci} 12048c2ecf20Sopenharmony_ci 12058c2ecf20Sopenharmony_cistatic void dquot_decr_inodes(struct dquot *dquot, qsize_t number) 12068c2ecf20Sopenharmony_ci{ 12078c2ecf20Sopenharmony_ci if (sb_dqopt(dquot->dq_sb)->flags & DQUOT_NEGATIVE_USAGE || 12088c2ecf20Sopenharmony_ci dquot->dq_dqb.dqb_curinodes >= number) 12098c2ecf20Sopenharmony_ci dquot->dq_dqb.dqb_curinodes -= number; 12108c2ecf20Sopenharmony_ci else 12118c2ecf20Sopenharmony_ci dquot->dq_dqb.dqb_curinodes = 0; 12128c2ecf20Sopenharmony_ci if (dquot->dq_dqb.dqb_curinodes <= dquot->dq_dqb.dqb_isoftlimit) 12138c2ecf20Sopenharmony_ci dquot->dq_dqb.dqb_itime = (time64_t) 0; 12148c2ecf20Sopenharmony_ci clear_bit(DQ_INODES_B, &dquot->dq_flags); 12158c2ecf20Sopenharmony_ci} 12168c2ecf20Sopenharmony_ci 12178c2ecf20Sopenharmony_cistatic void dquot_decr_space(struct dquot *dquot, qsize_t number) 12188c2ecf20Sopenharmony_ci{ 12198c2ecf20Sopenharmony_ci if (sb_dqopt(dquot->dq_sb)->flags & DQUOT_NEGATIVE_USAGE || 12208c2ecf20Sopenharmony_ci dquot->dq_dqb.dqb_curspace >= number) 12218c2ecf20Sopenharmony_ci dquot->dq_dqb.dqb_curspace -= number; 12228c2ecf20Sopenharmony_ci else 12238c2ecf20Sopenharmony_ci dquot->dq_dqb.dqb_curspace = 0; 12248c2ecf20Sopenharmony_ci if (dquot->dq_dqb.dqb_curspace + dquot->dq_dqb.dqb_rsvspace <= 12258c2ecf20Sopenharmony_ci dquot->dq_dqb.dqb_bsoftlimit) 12268c2ecf20Sopenharmony_ci dquot->dq_dqb.dqb_btime = (time64_t) 0; 12278c2ecf20Sopenharmony_ci clear_bit(DQ_BLKS_B, &dquot->dq_flags); 12288c2ecf20Sopenharmony_ci} 12298c2ecf20Sopenharmony_ci 12308c2ecf20Sopenharmony_cistruct dquot_warn { 12318c2ecf20Sopenharmony_ci struct super_block *w_sb; 12328c2ecf20Sopenharmony_ci struct kqid w_dq_id; 12338c2ecf20Sopenharmony_ci short w_type; 12348c2ecf20Sopenharmony_ci}; 12358c2ecf20Sopenharmony_ci 12368c2ecf20Sopenharmony_cistatic int warning_issued(struct dquot *dquot, const int warntype) 12378c2ecf20Sopenharmony_ci{ 12388c2ecf20Sopenharmony_ci int flag = (warntype == QUOTA_NL_BHARDWARN || 12398c2ecf20Sopenharmony_ci warntype == QUOTA_NL_BSOFTLONGWARN) ? DQ_BLKS_B : 12408c2ecf20Sopenharmony_ci ((warntype == QUOTA_NL_IHARDWARN || 12418c2ecf20Sopenharmony_ci warntype == QUOTA_NL_ISOFTLONGWARN) ? DQ_INODES_B : 0); 12428c2ecf20Sopenharmony_ci 12438c2ecf20Sopenharmony_ci if (!flag) 12448c2ecf20Sopenharmony_ci return 0; 12458c2ecf20Sopenharmony_ci return test_and_set_bit(flag, &dquot->dq_flags); 12468c2ecf20Sopenharmony_ci} 12478c2ecf20Sopenharmony_ci 12488c2ecf20Sopenharmony_ci#ifdef CONFIG_PRINT_QUOTA_WARNING 12498c2ecf20Sopenharmony_cistatic int flag_print_warnings = 1; 12508c2ecf20Sopenharmony_ci 12518c2ecf20Sopenharmony_cistatic int need_print_warning(struct dquot_warn *warn) 12528c2ecf20Sopenharmony_ci{ 12538c2ecf20Sopenharmony_ci if (!flag_print_warnings) 12548c2ecf20Sopenharmony_ci return 0; 12558c2ecf20Sopenharmony_ci 12568c2ecf20Sopenharmony_ci switch (warn->w_dq_id.type) { 12578c2ecf20Sopenharmony_ci case USRQUOTA: 12588c2ecf20Sopenharmony_ci return uid_eq(current_fsuid(), warn->w_dq_id.uid); 12598c2ecf20Sopenharmony_ci case GRPQUOTA: 12608c2ecf20Sopenharmony_ci return in_group_p(warn->w_dq_id.gid); 12618c2ecf20Sopenharmony_ci case PRJQUOTA: 12628c2ecf20Sopenharmony_ci return 1; 12638c2ecf20Sopenharmony_ci } 12648c2ecf20Sopenharmony_ci return 0; 12658c2ecf20Sopenharmony_ci} 12668c2ecf20Sopenharmony_ci 12678c2ecf20Sopenharmony_ci/* Print warning to user which exceeded quota */ 12688c2ecf20Sopenharmony_cistatic void print_warning(struct dquot_warn *warn) 12698c2ecf20Sopenharmony_ci{ 12708c2ecf20Sopenharmony_ci char *msg = NULL; 12718c2ecf20Sopenharmony_ci struct tty_struct *tty; 12728c2ecf20Sopenharmony_ci int warntype = warn->w_type; 12738c2ecf20Sopenharmony_ci 12748c2ecf20Sopenharmony_ci if (warntype == QUOTA_NL_IHARDBELOW || 12758c2ecf20Sopenharmony_ci warntype == QUOTA_NL_ISOFTBELOW || 12768c2ecf20Sopenharmony_ci warntype == QUOTA_NL_BHARDBELOW || 12778c2ecf20Sopenharmony_ci warntype == QUOTA_NL_BSOFTBELOW || !need_print_warning(warn)) 12788c2ecf20Sopenharmony_ci return; 12798c2ecf20Sopenharmony_ci 12808c2ecf20Sopenharmony_ci tty = get_current_tty(); 12818c2ecf20Sopenharmony_ci if (!tty) 12828c2ecf20Sopenharmony_ci return; 12838c2ecf20Sopenharmony_ci tty_write_message(tty, warn->w_sb->s_id); 12848c2ecf20Sopenharmony_ci if (warntype == QUOTA_NL_ISOFTWARN || warntype == QUOTA_NL_BSOFTWARN) 12858c2ecf20Sopenharmony_ci tty_write_message(tty, ": warning, "); 12868c2ecf20Sopenharmony_ci else 12878c2ecf20Sopenharmony_ci tty_write_message(tty, ": write failed, "); 12888c2ecf20Sopenharmony_ci tty_write_message(tty, quotatypes[warn->w_dq_id.type]); 12898c2ecf20Sopenharmony_ci switch (warntype) { 12908c2ecf20Sopenharmony_ci case QUOTA_NL_IHARDWARN: 12918c2ecf20Sopenharmony_ci msg = " file limit reached.\r\n"; 12928c2ecf20Sopenharmony_ci break; 12938c2ecf20Sopenharmony_ci case QUOTA_NL_ISOFTLONGWARN: 12948c2ecf20Sopenharmony_ci msg = " file quota exceeded too long.\r\n"; 12958c2ecf20Sopenharmony_ci break; 12968c2ecf20Sopenharmony_ci case QUOTA_NL_ISOFTWARN: 12978c2ecf20Sopenharmony_ci msg = " file quota exceeded.\r\n"; 12988c2ecf20Sopenharmony_ci break; 12998c2ecf20Sopenharmony_ci case QUOTA_NL_BHARDWARN: 13008c2ecf20Sopenharmony_ci msg = " block limit reached.\r\n"; 13018c2ecf20Sopenharmony_ci break; 13028c2ecf20Sopenharmony_ci case QUOTA_NL_BSOFTLONGWARN: 13038c2ecf20Sopenharmony_ci msg = " block quota exceeded too long.\r\n"; 13048c2ecf20Sopenharmony_ci break; 13058c2ecf20Sopenharmony_ci case QUOTA_NL_BSOFTWARN: 13068c2ecf20Sopenharmony_ci msg = " block quota exceeded.\r\n"; 13078c2ecf20Sopenharmony_ci break; 13088c2ecf20Sopenharmony_ci } 13098c2ecf20Sopenharmony_ci tty_write_message(tty, msg); 13108c2ecf20Sopenharmony_ci tty_kref_put(tty); 13118c2ecf20Sopenharmony_ci} 13128c2ecf20Sopenharmony_ci#endif 13138c2ecf20Sopenharmony_ci 13148c2ecf20Sopenharmony_cistatic void prepare_warning(struct dquot_warn *warn, struct dquot *dquot, 13158c2ecf20Sopenharmony_ci int warntype) 13168c2ecf20Sopenharmony_ci{ 13178c2ecf20Sopenharmony_ci if (warning_issued(dquot, warntype)) 13188c2ecf20Sopenharmony_ci return; 13198c2ecf20Sopenharmony_ci warn->w_type = warntype; 13208c2ecf20Sopenharmony_ci warn->w_sb = dquot->dq_sb; 13218c2ecf20Sopenharmony_ci warn->w_dq_id = dquot->dq_id; 13228c2ecf20Sopenharmony_ci} 13238c2ecf20Sopenharmony_ci 13248c2ecf20Sopenharmony_ci/* 13258c2ecf20Sopenharmony_ci * Write warnings to the console and send warning messages over netlink. 13268c2ecf20Sopenharmony_ci * 13278c2ecf20Sopenharmony_ci * Note that this function can call into tty and networking code. 13288c2ecf20Sopenharmony_ci */ 13298c2ecf20Sopenharmony_cistatic void flush_warnings(struct dquot_warn *warn) 13308c2ecf20Sopenharmony_ci{ 13318c2ecf20Sopenharmony_ci int i; 13328c2ecf20Sopenharmony_ci 13338c2ecf20Sopenharmony_ci for (i = 0; i < MAXQUOTAS; i++) { 13348c2ecf20Sopenharmony_ci if (warn[i].w_type == QUOTA_NL_NOWARN) 13358c2ecf20Sopenharmony_ci continue; 13368c2ecf20Sopenharmony_ci#ifdef CONFIG_PRINT_QUOTA_WARNING 13378c2ecf20Sopenharmony_ci print_warning(&warn[i]); 13388c2ecf20Sopenharmony_ci#endif 13398c2ecf20Sopenharmony_ci quota_send_warning(warn[i].w_dq_id, 13408c2ecf20Sopenharmony_ci warn[i].w_sb->s_dev, warn[i].w_type); 13418c2ecf20Sopenharmony_ci } 13428c2ecf20Sopenharmony_ci} 13438c2ecf20Sopenharmony_ci 13448c2ecf20Sopenharmony_cistatic int ignore_hardlimit(struct dquot *dquot) 13458c2ecf20Sopenharmony_ci{ 13468c2ecf20Sopenharmony_ci struct mem_dqinfo *info = &sb_dqopt(dquot->dq_sb)->info[dquot->dq_id.type]; 13478c2ecf20Sopenharmony_ci 13488c2ecf20Sopenharmony_ci return capable(CAP_SYS_RESOURCE) && 13498c2ecf20Sopenharmony_ci (info->dqi_format->qf_fmt_id != QFMT_VFS_OLD || 13508c2ecf20Sopenharmony_ci !(info->dqi_flags & DQF_ROOT_SQUASH)); 13518c2ecf20Sopenharmony_ci} 13528c2ecf20Sopenharmony_ci 13538c2ecf20Sopenharmony_cistatic int dquot_add_inodes(struct dquot *dquot, qsize_t inodes, 13548c2ecf20Sopenharmony_ci struct dquot_warn *warn) 13558c2ecf20Sopenharmony_ci{ 13568c2ecf20Sopenharmony_ci qsize_t newinodes; 13578c2ecf20Sopenharmony_ci int ret = 0; 13588c2ecf20Sopenharmony_ci 13598c2ecf20Sopenharmony_ci spin_lock(&dquot->dq_dqb_lock); 13608c2ecf20Sopenharmony_ci newinodes = dquot->dq_dqb.dqb_curinodes + inodes; 13618c2ecf20Sopenharmony_ci if (!sb_has_quota_limits_enabled(dquot->dq_sb, dquot->dq_id.type) || 13628c2ecf20Sopenharmony_ci test_bit(DQ_FAKE_B, &dquot->dq_flags)) 13638c2ecf20Sopenharmony_ci goto add; 13648c2ecf20Sopenharmony_ci 13658c2ecf20Sopenharmony_ci if (dquot->dq_dqb.dqb_ihardlimit && 13668c2ecf20Sopenharmony_ci newinodes > dquot->dq_dqb.dqb_ihardlimit && 13678c2ecf20Sopenharmony_ci !ignore_hardlimit(dquot)) { 13688c2ecf20Sopenharmony_ci prepare_warning(warn, dquot, QUOTA_NL_IHARDWARN); 13698c2ecf20Sopenharmony_ci ret = -EDQUOT; 13708c2ecf20Sopenharmony_ci goto out; 13718c2ecf20Sopenharmony_ci } 13728c2ecf20Sopenharmony_ci 13738c2ecf20Sopenharmony_ci if (dquot->dq_dqb.dqb_isoftlimit && 13748c2ecf20Sopenharmony_ci newinodes > dquot->dq_dqb.dqb_isoftlimit && 13758c2ecf20Sopenharmony_ci dquot->dq_dqb.dqb_itime && 13768c2ecf20Sopenharmony_ci ktime_get_real_seconds() >= dquot->dq_dqb.dqb_itime && 13778c2ecf20Sopenharmony_ci !ignore_hardlimit(dquot)) { 13788c2ecf20Sopenharmony_ci prepare_warning(warn, dquot, QUOTA_NL_ISOFTLONGWARN); 13798c2ecf20Sopenharmony_ci ret = -EDQUOT; 13808c2ecf20Sopenharmony_ci goto out; 13818c2ecf20Sopenharmony_ci } 13828c2ecf20Sopenharmony_ci 13838c2ecf20Sopenharmony_ci if (dquot->dq_dqb.dqb_isoftlimit && 13848c2ecf20Sopenharmony_ci newinodes > dquot->dq_dqb.dqb_isoftlimit && 13858c2ecf20Sopenharmony_ci dquot->dq_dqb.dqb_itime == 0) { 13868c2ecf20Sopenharmony_ci prepare_warning(warn, dquot, QUOTA_NL_ISOFTWARN); 13878c2ecf20Sopenharmony_ci dquot->dq_dqb.dqb_itime = ktime_get_real_seconds() + 13888c2ecf20Sopenharmony_ci sb_dqopt(dquot->dq_sb)->info[dquot->dq_id.type].dqi_igrace; 13898c2ecf20Sopenharmony_ci } 13908c2ecf20Sopenharmony_ciadd: 13918c2ecf20Sopenharmony_ci dquot->dq_dqb.dqb_curinodes = newinodes; 13928c2ecf20Sopenharmony_ci 13938c2ecf20Sopenharmony_ciout: 13948c2ecf20Sopenharmony_ci spin_unlock(&dquot->dq_dqb_lock); 13958c2ecf20Sopenharmony_ci return ret; 13968c2ecf20Sopenharmony_ci} 13978c2ecf20Sopenharmony_ci 13988c2ecf20Sopenharmony_cistatic int dquot_add_space(struct dquot *dquot, qsize_t space, 13998c2ecf20Sopenharmony_ci qsize_t rsv_space, unsigned int flags, 14008c2ecf20Sopenharmony_ci struct dquot_warn *warn) 14018c2ecf20Sopenharmony_ci{ 14028c2ecf20Sopenharmony_ci qsize_t tspace; 14038c2ecf20Sopenharmony_ci struct super_block *sb = dquot->dq_sb; 14048c2ecf20Sopenharmony_ci int ret = 0; 14058c2ecf20Sopenharmony_ci 14068c2ecf20Sopenharmony_ci spin_lock(&dquot->dq_dqb_lock); 14078c2ecf20Sopenharmony_ci if (!sb_has_quota_limits_enabled(sb, dquot->dq_id.type) || 14088c2ecf20Sopenharmony_ci test_bit(DQ_FAKE_B, &dquot->dq_flags)) 14098c2ecf20Sopenharmony_ci goto finish; 14108c2ecf20Sopenharmony_ci 14118c2ecf20Sopenharmony_ci tspace = dquot->dq_dqb.dqb_curspace + dquot->dq_dqb.dqb_rsvspace 14128c2ecf20Sopenharmony_ci + space + rsv_space; 14138c2ecf20Sopenharmony_ci 14148c2ecf20Sopenharmony_ci if (dquot->dq_dqb.dqb_bhardlimit && 14158c2ecf20Sopenharmony_ci tspace > dquot->dq_dqb.dqb_bhardlimit && 14168c2ecf20Sopenharmony_ci !ignore_hardlimit(dquot)) { 14178c2ecf20Sopenharmony_ci if (flags & DQUOT_SPACE_WARN) 14188c2ecf20Sopenharmony_ci prepare_warning(warn, dquot, QUOTA_NL_BHARDWARN); 14198c2ecf20Sopenharmony_ci ret = -EDQUOT; 14208c2ecf20Sopenharmony_ci goto finish; 14218c2ecf20Sopenharmony_ci } 14228c2ecf20Sopenharmony_ci 14238c2ecf20Sopenharmony_ci if (dquot->dq_dqb.dqb_bsoftlimit && 14248c2ecf20Sopenharmony_ci tspace > dquot->dq_dqb.dqb_bsoftlimit && 14258c2ecf20Sopenharmony_ci dquot->dq_dqb.dqb_btime && 14268c2ecf20Sopenharmony_ci ktime_get_real_seconds() >= dquot->dq_dqb.dqb_btime && 14278c2ecf20Sopenharmony_ci !ignore_hardlimit(dquot)) { 14288c2ecf20Sopenharmony_ci if (flags & DQUOT_SPACE_WARN) 14298c2ecf20Sopenharmony_ci prepare_warning(warn, dquot, QUOTA_NL_BSOFTLONGWARN); 14308c2ecf20Sopenharmony_ci ret = -EDQUOT; 14318c2ecf20Sopenharmony_ci goto finish; 14328c2ecf20Sopenharmony_ci } 14338c2ecf20Sopenharmony_ci 14348c2ecf20Sopenharmony_ci if (dquot->dq_dqb.dqb_bsoftlimit && 14358c2ecf20Sopenharmony_ci tspace > dquot->dq_dqb.dqb_bsoftlimit && 14368c2ecf20Sopenharmony_ci dquot->dq_dqb.dqb_btime == 0) { 14378c2ecf20Sopenharmony_ci if (flags & DQUOT_SPACE_WARN) { 14388c2ecf20Sopenharmony_ci prepare_warning(warn, dquot, QUOTA_NL_BSOFTWARN); 14398c2ecf20Sopenharmony_ci dquot->dq_dqb.dqb_btime = ktime_get_real_seconds() + 14408c2ecf20Sopenharmony_ci sb_dqopt(sb)->info[dquot->dq_id.type].dqi_bgrace; 14418c2ecf20Sopenharmony_ci } else { 14428c2ecf20Sopenharmony_ci /* 14438c2ecf20Sopenharmony_ci * We don't allow preallocation to exceed softlimit so exceeding will 14448c2ecf20Sopenharmony_ci * be always printed 14458c2ecf20Sopenharmony_ci */ 14468c2ecf20Sopenharmony_ci ret = -EDQUOT; 14478c2ecf20Sopenharmony_ci goto finish; 14488c2ecf20Sopenharmony_ci } 14498c2ecf20Sopenharmony_ci } 14508c2ecf20Sopenharmony_cifinish: 14518c2ecf20Sopenharmony_ci /* 14528c2ecf20Sopenharmony_ci * We have to be careful and go through warning generation & grace time 14538c2ecf20Sopenharmony_ci * setting even if DQUOT_SPACE_NOFAIL is set. That's why we check it 14548c2ecf20Sopenharmony_ci * only here... 14558c2ecf20Sopenharmony_ci */ 14568c2ecf20Sopenharmony_ci if (flags & DQUOT_SPACE_NOFAIL) 14578c2ecf20Sopenharmony_ci ret = 0; 14588c2ecf20Sopenharmony_ci if (!ret) { 14598c2ecf20Sopenharmony_ci dquot->dq_dqb.dqb_rsvspace += rsv_space; 14608c2ecf20Sopenharmony_ci dquot->dq_dqb.dqb_curspace += space; 14618c2ecf20Sopenharmony_ci } 14628c2ecf20Sopenharmony_ci spin_unlock(&dquot->dq_dqb_lock); 14638c2ecf20Sopenharmony_ci return ret; 14648c2ecf20Sopenharmony_ci} 14658c2ecf20Sopenharmony_ci 14668c2ecf20Sopenharmony_cistatic int info_idq_free(struct dquot *dquot, qsize_t inodes) 14678c2ecf20Sopenharmony_ci{ 14688c2ecf20Sopenharmony_ci qsize_t newinodes; 14698c2ecf20Sopenharmony_ci 14708c2ecf20Sopenharmony_ci if (test_bit(DQ_FAKE_B, &dquot->dq_flags) || 14718c2ecf20Sopenharmony_ci dquot->dq_dqb.dqb_curinodes <= dquot->dq_dqb.dqb_isoftlimit || 14728c2ecf20Sopenharmony_ci !sb_has_quota_limits_enabled(dquot->dq_sb, dquot->dq_id.type)) 14738c2ecf20Sopenharmony_ci return QUOTA_NL_NOWARN; 14748c2ecf20Sopenharmony_ci 14758c2ecf20Sopenharmony_ci newinodes = dquot->dq_dqb.dqb_curinodes - inodes; 14768c2ecf20Sopenharmony_ci if (newinodes <= dquot->dq_dqb.dqb_isoftlimit) 14778c2ecf20Sopenharmony_ci return QUOTA_NL_ISOFTBELOW; 14788c2ecf20Sopenharmony_ci if (dquot->dq_dqb.dqb_curinodes >= dquot->dq_dqb.dqb_ihardlimit && 14798c2ecf20Sopenharmony_ci newinodes < dquot->dq_dqb.dqb_ihardlimit) 14808c2ecf20Sopenharmony_ci return QUOTA_NL_IHARDBELOW; 14818c2ecf20Sopenharmony_ci return QUOTA_NL_NOWARN; 14828c2ecf20Sopenharmony_ci} 14838c2ecf20Sopenharmony_ci 14848c2ecf20Sopenharmony_cistatic int info_bdq_free(struct dquot *dquot, qsize_t space) 14858c2ecf20Sopenharmony_ci{ 14868c2ecf20Sopenharmony_ci qsize_t tspace; 14878c2ecf20Sopenharmony_ci 14888c2ecf20Sopenharmony_ci tspace = dquot->dq_dqb.dqb_curspace + dquot->dq_dqb.dqb_rsvspace; 14898c2ecf20Sopenharmony_ci 14908c2ecf20Sopenharmony_ci if (test_bit(DQ_FAKE_B, &dquot->dq_flags) || 14918c2ecf20Sopenharmony_ci tspace <= dquot->dq_dqb.dqb_bsoftlimit) 14928c2ecf20Sopenharmony_ci return QUOTA_NL_NOWARN; 14938c2ecf20Sopenharmony_ci 14948c2ecf20Sopenharmony_ci if (tspace - space <= dquot->dq_dqb.dqb_bsoftlimit) 14958c2ecf20Sopenharmony_ci return QUOTA_NL_BSOFTBELOW; 14968c2ecf20Sopenharmony_ci if (tspace >= dquot->dq_dqb.dqb_bhardlimit && 14978c2ecf20Sopenharmony_ci tspace - space < dquot->dq_dqb.dqb_bhardlimit) 14988c2ecf20Sopenharmony_ci return QUOTA_NL_BHARDBELOW; 14998c2ecf20Sopenharmony_ci return QUOTA_NL_NOWARN; 15008c2ecf20Sopenharmony_ci} 15018c2ecf20Sopenharmony_ci 15028c2ecf20Sopenharmony_cistatic int inode_quota_active(const struct inode *inode) 15038c2ecf20Sopenharmony_ci{ 15048c2ecf20Sopenharmony_ci struct super_block *sb = inode->i_sb; 15058c2ecf20Sopenharmony_ci 15068c2ecf20Sopenharmony_ci if (IS_NOQUOTA(inode)) 15078c2ecf20Sopenharmony_ci return 0; 15088c2ecf20Sopenharmony_ci return sb_any_quota_loaded(sb) & ~sb_any_quota_suspended(sb); 15098c2ecf20Sopenharmony_ci} 15108c2ecf20Sopenharmony_ci 15118c2ecf20Sopenharmony_ci/* 15128c2ecf20Sopenharmony_ci * Initialize quota pointers in inode 15138c2ecf20Sopenharmony_ci * 15148c2ecf20Sopenharmony_ci * It is better to call this function outside of any transaction as it 15158c2ecf20Sopenharmony_ci * might need a lot of space in journal for dquot structure allocation. 15168c2ecf20Sopenharmony_ci */ 15178c2ecf20Sopenharmony_cistatic int __dquot_initialize(struct inode *inode, int type) 15188c2ecf20Sopenharmony_ci{ 15198c2ecf20Sopenharmony_ci int cnt, init_needed = 0; 15208c2ecf20Sopenharmony_ci struct dquot **dquots, *got[MAXQUOTAS] = {}; 15218c2ecf20Sopenharmony_ci struct super_block *sb = inode->i_sb; 15228c2ecf20Sopenharmony_ci qsize_t rsv; 15238c2ecf20Sopenharmony_ci int ret = 0; 15248c2ecf20Sopenharmony_ci 15258c2ecf20Sopenharmony_ci if (!inode_quota_active(inode)) 15268c2ecf20Sopenharmony_ci return 0; 15278c2ecf20Sopenharmony_ci 15288c2ecf20Sopenharmony_ci dquots = i_dquot(inode); 15298c2ecf20Sopenharmony_ci 15308c2ecf20Sopenharmony_ci /* First get references to structures we might need. */ 15318c2ecf20Sopenharmony_ci for (cnt = 0; cnt < MAXQUOTAS; cnt++) { 15328c2ecf20Sopenharmony_ci struct kqid qid; 15338c2ecf20Sopenharmony_ci kprojid_t projid; 15348c2ecf20Sopenharmony_ci int rc; 15358c2ecf20Sopenharmony_ci struct dquot *dquot; 15368c2ecf20Sopenharmony_ci 15378c2ecf20Sopenharmony_ci if (type != -1 && cnt != type) 15388c2ecf20Sopenharmony_ci continue; 15398c2ecf20Sopenharmony_ci /* 15408c2ecf20Sopenharmony_ci * The i_dquot should have been initialized in most cases, 15418c2ecf20Sopenharmony_ci * we check it without locking here to avoid unnecessary 15428c2ecf20Sopenharmony_ci * dqget()/dqput() calls. 15438c2ecf20Sopenharmony_ci */ 15448c2ecf20Sopenharmony_ci if (dquots[cnt]) 15458c2ecf20Sopenharmony_ci continue; 15468c2ecf20Sopenharmony_ci 15478c2ecf20Sopenharmony_ci if (!sb_has_quota_active(sb, cnt)) 15488c2ecf20Sopenharmony_ci continue; 15498c2ecf20Sopenharmony_ci 15508c2ecf20Sopenharmony_ci init_needed = 1; 15518c2ecf20Sopenharmony_ci 15528c2ecf20Sopenharmony_ci switch (cnt) { 15538c2ecf20Sopenharmony_ci case USRQUOTA: 15548c2ecf20Sopenharmony_ci qid = make_kqid_uid(inode->i_uid); 15558c2ecf20Sopenharmony_ci break; 15568c2ecf20Sopenharmony_ci case GRPQUOTA: 15578c2ecf20Sopenharmony_ci qid = make_kqid_gid(inode->i_gid); 15588c2ecf20Sopenharmony_ci break; 15598c2ecf20Sopenharmony_ci case PRJQUOTA: 15608c2ecf20Sopenharmony_ci rc = inode->i_sb->dq_op->get_projid(inode, &projid); 15618c2ecf20Sopenharmony_ci if (rc) 15628c2ecf20Sopenharmony_ci continue; 15638c2ecf20Sopenharmony_ci qid = make_kqid_projid(projid); 15648c2ecf20Sopenharmony_ci break; 15658c2ecf20Sopenharmony_ci } 15668c2ecf20Sopenharmony_ci dquot = dqget(sb, qid); 15678c2ecf20Sopenharmony_ci if (IS_ERR(dquot)) { 15688c2ecf20Sopenharmony_ci /* We raced with somebody turning quotas off... */ 15698c2ecf20Sopenharmony_ci if (PTR_ERR(dquot) != -ESRCH) { 15708c2ecf20Sopenharmony_ci ret = PTR_ERR(dquot); 15718c2ecf20Sopenharmony_ci goto out_put; 15728c2ecf20Sopenharmony_ci } 15738c2ecf20Sopenharmony_ci dquot = NULL; 15748c2ecf20Sopenharmony_ci } 15758c2ecf20Sopenharmony_ci got[cnt] = dquot; 15768c2ecf20Sopenharmony_ci } 15778c2ecf20Sopenharmony_ci 15788c2ecf20Sopenharmony_ci /* All required i_dquot has been initialized */ 15798c2ecf20Sopenharmony_ci if (!init_needed) 15808c2ecf20Sopenharmony_ci return 0; 15818c2ecf20Sopenharmony_ci 15828c2ecf20Sopenharmony_ci spin_lock(&dq_data_lock); 15838c2ecf20Sopenharmony_ci if (IS_NOQUOTA(inode)) 15848c2ecf20Sopenharmony_ci goto out_lock; 15858c2ecf20Sopenharmony_ci for (cnt = 0; cnt < MAXQUOTAS; cnt++) { 15868c2ecf20Sopenharmony_ci if (type != -1 && cnt != type) 15878c2ecf20Sopenharmony_ci continue; 15888c2ecf20Sopenharmony_ci /* Avoid races with quotaoff() */ 15898c2ecf20Sopenharmony_ci if (!sb_has_quota_active(sb, cnt)) 15908c2ecf20Sopenharmony_ci continue; 15918c2ecf20Sopenharmony_ci /* We could race with quotaon or dqget() could have failed */ 15928c2ecf20Sopenharmony_ci if (!got[cnt]) 15938c2ecf20Sopenharmony_ci continue; 15948c2ecf20Sopenharmony_ci if (!dquots[cnt]) { 15958c2ecf20Sopenharmony_ci dquots[cnt] = got[cnt]; 15968c2ecf20Sopenharmony_ci got[cnt] = NULL; 15978c2ecf20Sopenharmony_ci /* 15988c2ecf20Sopenharmony_ci * Make quota reservation system happy if someone 15998c2ecf20Sopenharmony_ci * did a write before quota was turned on 16008c2ecf20Sopenharmony_ci */ 16018c2ecf20Sopenharmony_ci rsv = inode_get_rsv_space(inode); 16028c2ecf20Sopenharmony_ci if (unlikely(rsv)) { 16038c2ecf20Sopenharmony_ci spin_lock(&inode->i_lock); 16048c2ecf20Sopenharmony_ci /* Get reservation again under proper lock */ 16058c2ecf20Sopenharmony_ci rsv = __inode_get_rsv_space(inode); 16068c2ecf20Sopenharmony_ci spin_lock(&dquots[cnt]->dq_dqb_lock); 16078c2ecf20Sopenharmony_ci dquots[cnt]->dq_dqb.dqb_rsvspace += rsv; 16088c2ecf20Sopenharmony_ci spin_unlock(&dquots[cnt]->dq_dqb_lock); 16098c2ecf20Sopenharmony_ci spin_unlock(&inode->i_lock); 16108c2ecf20Sopenharmony_ci } 16118c2ecf20Sopenharmony_ci } 16128c2ecf20Sopenharmony_ci } 16138c2ecf20Sopenharmony_ciout_lock: 16148c2ecf20Sopenharmony_ci spin_unlock(&dq_data_lock); 16158c2ecf20Sopenharmony_ciout_put: 16168c2ecf20Sopenharmony_ci /* Drop unused references */ 16178c2ecf20Sopenharmony_ci dqput_all(got); 16188c2ecf20Sopenharmony_ci 16198c2ecf20Sopenharmony_ci return ret; 16208c2ecf20Sopenharmony_ci} 16218c2ecf20Sopenharmony_ci 16228c2ecf20Sopenharmony_ciint dquot_initialize(struct inode *inode) 16238c2ecf20Sopenharmony_ci{ 16248c2ecf20Sopenharmony_ci return __dquot_initialize(inode, -1); 16258c2ecf20Sopenharmony_ci} 16268c2ecf20Sopenharmony_ciEXPORT_SYMBOL(dquot_initialize); 16278c2ecf20Sopenharmony_ci 16288c2ecf20Sopenharmony_cibool dquot_initialize_needed(struct inode *inode) 16298c2ecf20Sopenharmony_ci{ 16308c2ecf20Sopenharmony_ci struct dquot **dquots; 16318c2ecf20Sopenharmony_ci int i; 16328c2ecf20Sopenharmony_ci 16338c2ecf20Sopenharmony_ci if (!inode_quota_active(inode)) 16348c2ecf20Sopenharmony_ci return false; 16358c2ecf20Sopenharmony_ci 16368c2ecf20Sopenharmony_ci dquots = i_dquot(inode); 16378c2ecf20Sopenharmony_ci for (i = 0; i < MAXQUOTAS; i++) 16388c2ecf20Sopenharmony_ci if (!dquots[i] && sb_has_quota_active(inode->i_sb, i)) 16398c2ecf20Sopenharmony_ci return true; 16408c2ecf20Sopenharmony_ci return false; 16418c2ecf20Sopenharmony_ci} 16428c2ecf20Sopenharmony_ciEXPORT_SYMBOL(dquot_initialize_needed); 16438c2ecf20Sopenharmony_ci 16448c2ecf20Sopenharmony_ci/* 16458c2ecf20Sopenharmony_ci * Release all quotas referenced by inode. 16468c2ecf20Sopenharmony_ci * 16478c2ecf20Sopenharmony_ci * This function only be called on inode free or converting 16488c2ecf20Sopenharmony_ci * a file to quota file, no other users for the i_dquot in 16498c2ecf20Sopenharmony_ci * both cases, so we needn't call synchronize_srcu() after 16508c2ecf20Sopenharmony_ci * clearing i_dquot. 16518c2ecf20Sopenharmony_ci */ 16528c2ecf20Sopenharmony_cistatic void __dquot_drop(struct inode *inode) 16538c2ecf20Sopenharmony_ci{ 16548c2ecf20Sopenharmony_ci int cnt; 16558c2ecf20Sopenharmony_ci struct dquot **dquots = i_dquot(inode); 16568c2ecf20Sopenharmony_ci struct dquot *put[MAXQUOTAS]; 16578c2ecf20Sopenharmony_ci 16588c2ecf20Sopenharmony_ci spin_lock(&dq_data_lock); 16598c2ecf20Sopenharmony_ci for (cnt = 0; cnt < MAXQUOTAS; cnt++) { 16608c2ecf20Sopenharmony_ci put[cnt] = dquots[cnt]; 16618c2ecf20Sopenharmony_ci dquots[cnt] = NULL; 16628c2ecf20Sopenharmony_ci } 16638c2ecf20Sopenharmony_ci spin_unlock(&dq_data_lock); 16648c2ecf20Sopenharmony_ci dqput_all(put); 16658c2ecf20Sopenharmony_ci} 16668c2ecf20Sopenharmony_ci 16678c2ecf20Sopenharmony_civoid dquot_drop(struct inode *inode) 16688c2ecf20Sopenharmony_ci{ 16698c2ecf20Sopenharmony_ci struct dquot * const *dquots; 16708c2ecf20Sopenharmony_ci int cnt; 16718c2ecf20Sopenharmony_ci 16728c2ecf20Sopenharmony_ci if (IS_NOQUOTA(inode)) 16738c2ecf20Sopenharmony_ci return; 16748c2ecf20Sopenharmony_ci 16758c2ecf20Sopenharmony_ci /* 16768c2ecf20Sopenharmony_ci * Test before calling to rule out calls from proc and such 16778c2ecf20Sopenharmony_ci * where we are not allowed to block. Note that this is 16788c2ecf20Sopenharmony_ci * actually reliable test even without the lock - the caller 16798c2ecf20Sopenharmony_ci * must assure that nobody can come after the DQUOT_DROP and 16808c2ecf20Sopenharmony_ci * add quota pointers back anyway. 16818c2ecf20Sopenharmony_ci */ 16828c2ecf20Sopenharmony_ci dquots = i_dquot(inode); 16838c2ecf20Sopenharmony_ci for (cnt = 0; cnt < MAXQUOTAS; cnt++) { 16848c2ecf20Sopenharmony_ci if (dquots[cnt]) 16858c2ecf20Sopenharmony_ci break; 16868c2ecf20Sopenharmony_ci } 16878c2ecf20Sopenharmony_ci 16888c2ecf20Sopenharmony_ci if (cnt < MAXQUOTAS) 16898c2ecf20Sopenharmony_ci __dquot_drop(inode); 16908c2ecf20Sopenharmony_ci} 16918c2ecf20Sopenharmony_ciEXPORT_SYMBOL(dquot_drop); 16928c2ecf20Sopenharmony_ci 16938c2ecf20Sopenharmony_ci/* 16948c2ecf20Sopenharmony_ci * inode_reserved_space is managed internally by quota, and protected by 16958c2ecf20Sopenharmony_ci * i_lock similar to i_blocks+i_bytes. 16968c2ecf20Sopenharmony_ci */ 16978c2ecf20Sopenharmony_cistatic qsize_t *inode_reserved_space(struct inode * inode) 16988c2ecf20Sopenharmony_ci{ 16998c2ecf20Sopenharmony_ci /* Filesystem must explicitly define it's own method in order to use 17008c2ecf20Sopenharmony_ci * quota reservation interface */ 17018c2ecf20Sopenharmony_ci BUG_ON(!inode->i_sb->dq_op->get_reserved_space); 17028c2ecf20Sopenharmony_ci return inode->i_sb->dq_op->get_reserved_space(inode); 17038c2ecf20Sopenharmony_ci} 17048c2ecf20Sopenharmony_ci 17058c2ecf20Sopenharmony_cistatic qsize_t __inode_get_rsv_space(struct inode *inode) 17068c2ecf20Sopenharmony_ci{ 17078c2ecf20Sopenharmony_ci if (!inode->i_sb->dq_op->get_reserved_space) 17088c2ecf20Sopenharmony_ci return 0; 17098c2ecf20Sopenharmony_ci return *inode_reserved_space(inode); 17108c2ecf20Sopenharmony_ci} 17118c2ecf20Sopenharmony_ci 17128c2ecf20Sopenharmony_cistatic qsize_t inode_get_rsv_space(struct inode *inode) 17138c2ecf20Sopenharmony_ci{ 17148c2ecf20Sopenharmony_ci qsize_t ret; 17158c2ecf20Sopenharmony_ci 17168c2ecf20Sopenharmony_ci if (!inode->i_sb->dq_op->get_reserved_space) 17178c2ecf20Sopenharmony_ci return 0; 17188c2ecf20Sopenharmony_ci spin_lock(&inode->i_lock); 17198c2ecf20Sopenharmony_ci ret = __inode_get_rsv_space(inode); 17208c2ecf20Sopenharmony_ci spin_unlock(&inode->i_lock); 17218c2ecf20Sopenharmony_ci return ret; 17228c2ecf20Sopenharmony_ci} 17238c2ecf20Sopenharmony_ci 17248c2ecf20Sopenharmony_ci/* 17258c2ecf20Sopenharmony_ci * This functions updates i_blocks+i_bytes fields and quota information 17268c2ecf20Sopenharmony_ci * (together with appropriate checks). 17278c2ecf20Sopenharmony_ci * 17288c2ecf20Sopenharmony_ci * NOTE: We absolutely rely on the fact that caller dirties the inode 17298c2ecf20Sopenharmony_ci * (usually helpers in quotaops.h care about this) and holds a handle for 17308c2ecf20Sopenharmony_ci * the current transaction so that dquot write and inode write go into the 17318c2ecf20Sopenharmony_ci * same transaction. 17328c2ecf20Sopenharmony_ci */ 17338c2ecf20Sopenharmony_ci 17348c2ecf20Sopenharmony_ci/* 17358c2ecf20Sopenharmony_ci * This operation can block, but only after everything is updated 17368c2ecf20Sopenharmony_ci */ 17378c2ecf20Sopenharmony_ciint __dquot_alloc_space(struct inode *inode, qsize_t number, int flags) 17388c2ecf20Sopenharmony_ci{ 17398c2ecf20Sopenharmony_ci int cnt, ret = 0, index; 17408c2ecf20Sopenharmony_ci struct dquot_warn warn[MAXQUOTAS]; 17418c2ecf20Sopenharmony_ci int reserve = flags & DQUOT_SPACE_RESERVE; 17428c2ecf20Sopenharmony_ci struct dquot **dquots; 17438c2ecf20Sopenharmony_ci struct dquot *dquot; 17448c2ecf20Sopenharmony_ci 17458c2ecf20Sopenharmony_ci if (!inode_quota_active(inode)) { 17468c2ecf20Sopenharmony_ci if (reserve) { 17478c2ecf20Sopenharmony_ci spin_lock(&inode->i_lock); 17488c2ecf20Sopenharmony_ci *inode_reserved_space(inode) += number; 17498c2ecf20Sopenharmony_ci spin_unlock(&inode->i_lock); 17508c2ecf20Sopenharmony_ci } else { 17518c2ecf20Sopenharmony_ci inode_add_bytes(inode, number); 17528c2ecf20Sopenharmony_ci } 17538c2ecf20Sopenharmony_ci goto out; 17548c2ecf20Sopenharmony_ci } 17558c2ecf20Sopenharmony_ci 17568c2ecf20Sopenharmony_ci for (cnt = 0; cnt < MAXQUOTAS; cnt++) 17578c2ecf20Sopenharmony_ci warn[cnt].w_type = QUOTA_NL_NOWARN; 17588c2ecf20Sopenharmony_ci 17598c2ecf20Sopenharmony_ci dquots = i_dquot(inode); 17608c2ecf20Sopenharmony_ci index = srcu_read_lock(&dquot_srcu); 17618c2ecf20Sopenharmony_ci spin_lock(&inode->i_lock); 17628c2ecf20Sopenharmony_ci for (cnt = 0; cnt < MAXQUOTAS; cnt++) { 17638c2ecf20Sopenharmony_ci dquot = srcu_dereference(dquots[cnt], &dquot_srcu); 17648c2ecf20Sopenharmony_ci if (!dquot) 17658c2ecf20Sopenharmony_ci continue; 17668c2ecf20Sopenharmony_ci if (reserve) { 17678c2ecf20Sopenharmony_ci ret = dquot_add_space(dquot, 0, number, flags, &warn[cnt]); 17688c2ecf20Sopenharmony_ci } else { 17698c2ecf20Sopenharmony_ci ret = dquot_add_space(dquot, number, 0, flags, &warn[cnt]); 17708c2ecf20Sopenharmony_ci } 17718c2ecf20Sopenharmony_ci if (ret) { 17728c2ecf20Sopenharmony_ci /* Back out changes we already did */ 17738c2ecf20Sopenharmony_ci for (cnt--; cnt >= 0; cnt--) { 17748c2ecf20Sopenharmony_ci dquot = srcu_dereference(dquots[cnt], &dquot_srcu); 17758c2ecf20Sopenharmony_ci if (!dquot) 17768c2ecf20Sopenharmony_ci continue; 17778c2ecf20Sopenharmony_ci spin_lock(&dquot->dq_dqb_lock); 17788c2ecf20Sopenharmony_ci if (reserve) 17798c2ecf20Sopenharmony_ci dquot_free_reserved_space(dquot, number); 17808c2ecf20Sopenharmony_ci else 17818c2ecf20Sopenharmony_ci dquot_decr_space(dquot, number); 17828c2ecf20Sopenharmony_ci spin_unlock(&dquot->dq_dqb_lock); 17838c2ecf20Sopenharmony_ci } 17848c2ecf20Sopenharmony_ci spin_unlock(&inode->i_lock); 17858c2ecf20Sopenharmony_ci goto out_flush_warn; 17868c2ecf20Sopenharmony_ci } 17878c2ecf20Sopenharmony_ci } 17888c2ecf20Sopenharmony_ci if (reserve) 17898c2ecf20Sopenharmony_ci *inode_reserved_space(inode) += number; 17908c2ecf20Sopenharmony_ci else 17918c2ecf20Sopenharmony_ci __inode_add_bytes(inode, number); 17928c2ecf20Sopenharmony_ci spin_unlock(&inode->i_lock); 17938c2ecf20Sopenharmony_ci 17948c2ecf20Sopenharmony_ci if (reserve) 17958c2ecf20Sopenharmony_ci goto out_flush_warn; 17968c2ecf20Sopenharmony_ci mark_all_dquot_dirty(dquots); 17978c2ecf20Sopenharmony_ciout_flush_warn: 17988c2ecf20Sopenharmony_ci srcu_read_unlock(&dquot_srcu, index); 17998c2ecf20Sopenharmony_ci flush_warnings(warn); 18008c2ecf20Sopenharmony_ciout: 18018c2ecf20Sopenharmony_ci return ret; 18028c2ecf20Sopenharmony_ci} 18038c2ecf20Sopenharmony_ciEXPORT_SYMBOL(__dquot_alloc_space); 18048c2ecf20Sopenharmony_ci 18058c2ecf20Sopenharmony_ci/* 18068c2ecf20Sopenharmony_ci * This operation can block, but only after everything is updated 18078c2ecf20Sopenharmony_ci */ 18088c2ecf20Sopenharmony_ciint dquot_alloc_inode(struct inode *inode) 18098c2ecf20Sopenharmony_ci{ 18108c2ecf20Sopenharmony_ci int cnt, ret = 0, index; 18118c2ecf20Sopenharmony_ci struct dquot_warn warn[MAXQUOTAS]; 18128c2ecf20Sopenharmony_ci struct dquot * const *dquots; 18138c2ecf20Sopenharmony_ci struct dquot *dquot; 18148c2ecf20Sopenharmony_ci 18158c2ecf20Sopenharmony_ci if (!inode_quota_active(inode)) 18168c2ecf20Sopenharmony_ci return 0; 18178c2ecf20Sopenharmony_ci for (cnt = 0; cnt < MAXQUOTAS; cnt++) 18188c2ecf20Sopenharmony_ci warn[cnt].w_type = QUOTA_NL_NOWARN; 18198c2ecf20Sopenharmony_ci 18208c2ecf20Sopenharmony_ci dquots = i_dquot(inode); 18218c2ecf20Sopenharmony_ci index = srcu_read_lock(&dquot_srcu); 18228c2ecf20Sopenharmony_ci spin_lock(&inode->i_lock); 18238c2ecf20Sopenharmony_ci for (cnt = 0; cnt < MAXQUOTAS; cnt++) { 18248c2ecf20Sopenharmony_ci dquot = srcu_dereference(dquots[cnt], &dquot_srcu); 18258c2ecf20Sopenharmony_ci if (!dquot) 18268c2ecf20Sopenharmony_ci continue; 18278c2ecf20Sopenharmony_ci ret = dquot_add_inodes(dquot, 1, &warn[cnt]); 18288c2ecf20Sopenharmony_ci if (ret) { 18298c2ecf20Sopenharmony_ci for (cnt--; cnt >= 0; cnt--) { 18308c2ecf20Sopenharmony_ci dquot = srcu_dereference(dquots[cnt], &dquot_srcu); 18318c2ecf20Sopenharmony_ci if (!dquot) 18328c2ecf20Sopenharmony_ci continue; 18338c2ecf20Sopenharmony_ci /* Back out changes we already did */ 18348c2ecf20Sopenharmony_ci spin_lock(&dquot->dq_dqb_lock); 18358c2ecf20Sopenharmony_ci dquot_decr_inodes(dquot, 1); 18368c2ecf20Sopenharmony_ci spin_unlock(&dquot->dq_dqb_lock); 18378c2ecf20Sopenharmony_ci } 18388c2ecf20Sopenharmony_ci goto warn_put_all; 18398c2ecf20Sopenharmony_ci } 18408c2ecf20Sopenharmony_ci } 18418c2ecf20Sopenharmony_ci 18428c2ecf20Sopenharmony_ciwarn_put_all: 18438c2ecf20Sopenharmony_ci spin_unlock(&inode->i_lock); 18448c2ecf20Sopenharmony_ci if (ret == 0) 18458c2ecf20Sopenharmony_ci mark_all_dquot_dirty(dquots); 18468c2ecf20Sopenharmony_ci srcu_read_unlock(&dquot_srcu, index); 18478c2ecf20Sopenharmony_ci flush_warnings(warn); 18488c2ecf20Sopenharmony_ci return ret; 18498c2ecf20Sopenharmony_ci} 18508c2ecf20Sopenharmony_ciEXPORT_SYMBOL(dquot_alloc_inode); 18518c2ecf20Sopenharmony_ci 18528c2ecf20Sopenharmony_ci/* 18538c2ecf20Sopenharmony_ci * Convert in-memory reserved quotas to real consumed quotas 18548c2ecf20Sopenharmony_ci */ 18558c2ecf20Sopenharmony_ciint dquot_claim_space_nodirty(struct inode *inode, qsize_t number) 18568c2ecf20Sopenharmony_ci{ 18578c2ecf20Sopenharmony_ci struct dquot **dquots; 18588c2ecf20Sopenharmony_ci struct dquot *dquot; 18598c2ecf20Sopenharmony_ci int cnt, index; 18608c2ecf20Sopenharmony_ci 18618c2ecf20Sopenharmony_ci if (!inode_quota_active(inode)) { 18628c2ecf20Sopenharmony_ci spin_lock(&inode->i_lock); 18638c2ecf20Sopenharmony_ci *inode_reserved_space(inode) -= number; 18648c2ecf20Sopenharmony_ci __inode_add_bytes(inode, number); 18658c2ecf20Sopenharmony_ci spin_unlock(&inode->i_lock); 18668c2ecf20Sopenharmony_ci return 0; 18678c2ecf20Sopenharmony_ci } 18688c2ecf20Sopenharmony_ci 18698c2ecf20Sopenharmony_ci dquots = i_dquot(inode); 18708c2ecf20Sopenharmony_ci index = srcu_read_lock(&dquot_srcu); 18718c2ecf20Sopenharmony_ci spin_lock(&inode->i_lock); 18728c2ecf20Sopenharmony_ci /* Claim reserved quotas to allocated quotas */ 18738c2ecf20Sopenharmony_ci for (cnt = 0; cnt < MAXQUOTAS; cnt++) { 18748c2ecf20Sopenharmony_ci dquot = srcu_dereference(dquots[cnt], &dquot_srcu); 18758c2ecf20Sopenharmony_ci if (dquot) { 18768c2ecf20Sopenharmony_ci spin_lock(&dquot->dq_dqb_lock); 18778c2ecf20Sopenharmony_ci if (WARN_ON_ONCE(dquot->dq_dqb.dqb_rsvspace < number)) 18788c2ecf20Sopenharmony_ci number = dquot->dq_dqb.dqb_rsvspace; 18798c2ecf20Sopenharmony_ci dquot->dq_dqb.dqb_curspace += number; 18808c2ecf20Sopenharmony_ci dquot->dq_dqb.dqb_rsvspace -= number; 18818c2ecf20Sopenharmony_ci spin_unlock(&dquot->dq_dqb_lock); 18828c2ecf20Sopenharmony_ci } 18838c2ecf20Sopenharmony_ci } 18848c2ecf20Sopenharmony_ci /* Update inode bytes */ 18858c2ecf20Sopenharmony_ci *inode_reserved_space(inode) -= number; 18868c2ecf20Sopenharmony_ci __inode_add_bytes(inode, number); 18878c2ecf20Sopenharmony_ci spin_unlock(&inode->i_lock); 18888c2ecf20Sopenharmony_ci mark_all_dquot_dirty(dquots); 18898c2ecf20Sopenharmony_ci srcu_read_unlock(&dquot_srcu, index); 18908c2ecf20Sopenharmony_ci return 0; 18918c2ecf20Sopenharmony_ci} 18928c2ecf20Sopenharmony_ciEXPORT_SYMBOL(dquot_claim_space_nodirty); 18938c2ecf20Sopenharmony_ci 18948c2ecf20Sopenharmony_ci/* 18958c2ecf20Sopenharmony_ci * Convert allocated space back to in-memory reserved quotas 18968c2ecf20Sopenharmony_ci */ 18978c2ecf20Sopenharmony_civoid dquot_reclaim_space_nodirty(struct inode *inode, qsize_t number) 18988c2ecf20Sopenharmony_ci{ 18998c2ecf20Sopenharmony_ci struct dquot **dquots; 19008c2ecf20Sopenharmony_ci struct dquot *dquot; 19018c2ecf20Sopenharmony_ci int cnt, index; 19028c2ecf20Sopenharmony_ci 19038c2ecf20Sopenharmony_ci if (!inode_quota_active(inode)) { 19048c2ecf20Sopenharmony_ci spin_lock(&inode->i_lock); 19058c2ecf20Sopenharmony_ci *inode_reserved_space(inode) += number; 19068c2ecf20Sopenharmony_ci __inode_sub_bytes(inode, number); 19078c2ecf20Sopenharmony_ci spin_unlock(&inode->i_lock); 19088c2ecf20Sopenharmony_ci return; 19098c2ecf20Sopenharmony_ci } 19108c2ecf20Sopenharmony_ci 19118c2ecf20Sopenharmony_ci dquots = i_dquot(inode); 19128c2ecf20Sopenharmony_ci index = srcu_read_lock(&dquot_srcu); 19138c2ecf20Sopenharmony_ci spin_lock(&inode->i_lock); 19148c2ecf20Sopenharmony_ci /* Claim reserved quotas to allocated quotas */ 19158c2ecf20Sopenharmony_ci for (cnt = 0; cnt < MAXQUOTAS; cnt++) { 19168c2ecf20Sopenharmony_ci dquot = srcu_dereference(dquots[cnt], &dquot_srcu); 19178c2ecf20Sopenharmony_ci if (dquot) { 19188c2ecf20Sopenharmony_ci spin_lock(&dquot->dq_dqb_lock); 19198c2ecf20Sopenharmony_ci if (WARN_ON_ONCE(dquot->dq_dqb.dqb_curspace < number)) 19208c2ecf20Sopenharmony_ci number = dquot->dq_dqb.dqb_curspace; 19218c2ecf20Sopenharmony_ci dquot->dq_dqb.dqb_rsvspace += number; 19228c2ecf20Sopenharmony_ci dquot->dq_dqb.dqb_curspace -= number; 19238c2ecf20Sopenharmony_ci spin_unlock(&dquot->dq_dqb_lock); 19248c2ecf20Sopenharmony_ci } 19258c2ecf20Sopenharmony_ci } 19268c2ecf20Sopenharmony_ci /* Update inode bytes */ 19278c2ecf20Sopenharmony_ci *inode_reserved_space(inode) += number; 19288c2ecf20Sopenharmony_ci __inode_sub_bytes(inode, number); 19298c2ecf20Sopenharmony_ci spin_unlock(&inode->i_lock); 19308c2ecf20Sopenharmony_ci mark_all_dquot_dirty(dquots); 19318c2ecf20Sopenharmony_ci srcu_read_unlock(&dquot_srcu, index); 19328c2ecf20Sopenharmony_ci return; 19338c2ecf20Sopenharmony_ci} 19348c2ecf20Sopenharmony_ciEXPORT_SYMBOL(dquot_reclaim_space_nodirty); 19358c2ecf20Sopenharmony_ci 19368c2ecf20Sopenharmony_ci/* 19378c2ecf20Sopenharmony_ci * This operation can block, but only after everything is updated 19388c2ecf20Sopenharmony_ci */ 19398c2ecf20Sopenharmony_civoid __dquot_free_space(struct inode *inode, qsize_t number, int flags) 19408c2ecf20Sopenharmony_ci{ 19418c2ecf20Sopenharmony_ci unsigned int cnt; 19428c2ecf20Sopenharmony_ci struct dquot_warn warn[MAXQUOTAS]; 19438c2ecf20Sopenharmony_ci struct dquot **dquots; 19448c2ecf20Sopenharmony_ci struct dquot *dquot; 19458c2ecf20Sopenharmony_ci int reserve = flags & DQUOT_SPACE_RESERVE, index; 19468c2ecf20Sopenharmony_ci 19478c2ecf20Sopenharmony_ci if (!inode_quota_active(inode)) { 19488c2ecf20Sopenharmony_ci if (reserve) { 19498c2ecf20Sopenharmony_ci spin_lock(&inode->i_lock); 19508c2ecf20Sopenharmony_ci *inode_reserved_space(inode) -= number; 19518c2ecf20Sopenharmony_ci spin_unlock(&inode->i_lock); 19528c2ecf20Sopenharmony_ci } else { 19538c2ecf20Sopenharmony_ci inode_sub_bytes(inode, number); 19548c2ecf20Sopenharmony_ci } 19558c2ecf20Sopenharmony_ci return; 19568c2ecf20Sopenharmony_ci } 19578c2ecf20Sopenharmony_ci 19588c2ecf20Sopenharmony_ci dquots = i_dquot(inode); 19598c2ecf20Sopenharmony_ci index = srcu_read_lock(&dquot_srcu); 19608c2ecf20Sopenharmony_ci spin_lock(&inode->i_lock); 19618c2ecf20Sopenharmony_ci for (cnt = 0; cnt < MAXQUOTAS; cnt++) { 19628c2ecf20Sopenharmony_ci int wtype; 19638c2ecf20Sopenharmony_ci 19648c2ecf20Sopenharmony_ci warn[cnt].w_type = QUOTA_NL_NOWARN; 19658c2ecf20Sopenharmony_ci dquot = srcu_dereference(dquots[cnt], &dquot_srcu); 19668c2ecf20Sopenharmony_ci if (!dquot) 19678c2ecf20Sopenharmony_ci continue; 19688c2ecf20Sopenharmony_ci spin_lock(&dquot->dq_dqb_lock); 19698c2ecf20Sopenharmony_ci wtype = info_bdq_free(dquot, number); 19708c2ecf20Sopenharmony_ci if (wtype != QUOTA_NL_NOWARN) 19718c2ecf20Sopenharmony_ci prepare_warning(&warn[cnt], dquot, wtype); 19728c2ecf20Sopenharmony_ci if (reserve) 19738c2ecf20Sopenharmony_ci dquot_free_reserved_space(dquot, number); 19748c2ecf20Sopenharmony_ci else 19758c2ecf20Sopenharmony_ci dquot_decr_space(dquot, number); 19768c2ecf20Sopenharmony_ci spin_unlock(&dquot->dq_dqb_lock); 19778c2ecf20Sopenharmony_ci } 19788c2ecf20Sopenharmony_ci if (reserve) 19798c2ecf20Sopenharmony_ci *inode_reserved_space(inode) -= number; 19808c2ecf20Sopenharmony_ci else 19818c2ecf20Sopenharmony_ci __inode_sub_bytes(inode, number); 19828c2ecf20Sopenharmony_ci spin_unlock(&inode->i_lock); 19838c2ecf20Sopenharmony_ci 19848c2ecf20Sopenharmony_ci if (reserve) 19858c2ecf20Sopenharmony_ci goto out_unlock; 19868c2ecf20Sopenharmony_ci mark_all_dquot_dirty(dquots); 19878c2ecf20Sopenharmony_ciout_unlock: 19888c2ecf20Sopenharmony_ci srcu_read_unlock(&dquot_srcu, index); 19898c2ecf20Sopenharmony_ci flush_warnings(warn); 19908c2ecf20Sopenharmony_ci} 19918c2ecf20Sopenharmony_ciEXPORT_SYMBOL(__dquot_free_space); 19928c2ecf20Sopenharmony_ci 19938c2ecf20Sopenharmony_ci/* 19948c2ecf20Sopenharmony_ci * This operation can block, but only after everything is updated 19958c2ecf20Sopenharmony_ci */ 19968c2ecf20Sopenharmony_civoid dquot_free_inode(struct inode *inode) 19978c2ecf20Sopenharmony_ci{ 19988c2ecf20Sopenharmony_ci unsigned int cnt; 19998c2ecf20Sopenharmony_ci struct dquot_warn warn[MAXQUOTAS]; 20008c2ecf20Sopenharmony_ci struct dquot * const *dquots; 20018c2ecf20Sopenharmony_ci struct dquot *dquot; 20028c2ecf20Sopenharmony_ci int index; 20038c2ecf20Sopenharmony_ci 20048c2ecf20Sopenharmony_ci if (!inode_quota_active(inode)) 20058c2ecf20Sopenharmony_ci return; 20068c2ecf20Sopenharmony_ci 20078c2ecf20Sopenharmony_ci dquots = i_dquot(inode); 20088c2ecf20Sopenharmony_ci index = srcu_read_lock(&dquot_srcu); 20098c2ecf20Sopenharmony_ci spin_lock(&inode->i_lock); 20108c2ecf20Sopenharmony_ci for (cnt = 0; cnt < MAXQUOTAS; cnt++) { 20118c2ecf20Sopenharmony_ci int wtype; 20128c2ecf20Sopenharmony_ci warn[cnt].w_type = QUOTA_NL_NOWARN; 20138c2ecf20Sopenharmony_ci dquot = srcu_dereference(dquots[cnt], &dquot_srcu); 20148c2ecf20Sopenharmony_ci if (!dquot) 20158c2ecf20Sopenharmony_ci continue; 20168c2ecf20Sopenharmony_ci spin_lock(&dquot->dq_dqb_lock); 20178c2ecf20Sopenharmony_ci wtype = info_idq_free(dquot, 1); 20188c2ecf20Sopenharmony_ci if (wtype != QUOTA_NL_NOWARN) 20198c2ecf20Sopenharmony_ci prepare_warning(&warn[cnt], dquot, wtype); 20208c2ecf20Sopenharmony_ci dquot_decr_inodes(dquot, 1); 20218c2ecf20Sopenharmony_ci spin_unlock(&dquot->dq_dqb_lock); 20228c2ecf20Sopenharmony_ci } 20238c2ecf20Sopenharmony_ci spin_unlock(&inode->i_lock); 20248c2ecf20Sopenharmony_ci mark_all_dquot_dirty(dquots); 20258c2ecf20Sopenharmony_ci srcu_read_unlock(&dquot_srcu, index); 20268c2ecf20Sopenharmony_ci flush_warnings(warn); 20278c2ecf20Sopenharmony_ci} 20288c2ecf20Sopenharmony_ciEXPORT_SYMBOL(dquot_free_inode); 20298c2ecf20Sopenharmony_ci 20308c2ecf20Sopenharmony_ci/* 20318c2ecf20Sopenharmony_ci * Transfer the number of inode and blocks from one diskquota to an other. 20328c2ecf20Sopenharmony_ci * On success, dquot references in transfer_to are consumed and references 20338c2ecf20Sopenharmony_ci * to original dquots that need to be released are placed there. On failure, 20348c2ecf20Sopenharmony_ci * references are kept untouched. 20358c2ecf20Sopenharmony_ci * 20368c2ecf20Sopenharmony_ci * This operation can block, but only after everything is updated 20378c2ecf20Sopenharmony_ci * A transaction must be started when entering this function. 20388c2ecf20Sopenharmony_ci * 20398c2ecf20Sopenharmony_ci * We are holding reference on transfer_from & transfer_to, no need to 20408c2ecf20Sopenharmony_ci * protect them by srcu_read_lock(). 20418c2ecf20Sopenharmony_ci */ 20428c2ecf20Sopenharmony_ciint __dquot_transfer(struct inode *inode, struct dquot **transfer_to) 20438c2ecf20Sopenharmony_ci{ 20448c2ecf20Sopenharmony_ci qsize_t cur_space; 20458c2ecf20Sopenharmony_ci qsize_t rsv_space = 0; 20468c2ecf20Sopenharmony_ci qsize_t inode_usage = 1; 20478c2ecf20Sopenharmony_ci struct dquot *transfer_from[MAXQUOTAS] = {}; 20488c2ecf20Sopenharmony_ci int cnt, index, ret = 0; 20498c2ecf20Sopenharmony_ci char is_valid[MAXQUOTAS] = {}; 20508c2ecf20Sopenharmony_ci struct dquot_warn warn_to[MAXQUOTAS]; 20518c2ecf20Sopenharmony_ci struct dquot_warn warn_from_inodes[MAXQUOTAS]; 20528c2ecf20Sopenharmony_ci struct dquot_warn warn_from_space[MAXQUOTAS]; 20538c2ecf20Sopenharmony_ci 20548c2ecf20Sopenharmony_ci if (IS_NOQUOTA(inode)) 20558c2ecf20Sopenharmony_ci return 0; 20568c2ecf20Sopenharmony_ci 20578c2ecf20Sopenharmony_ci if (inode->i_sb->dq_op->get_inode_usage) { 20588c2ecf20Sopenharmony_ci ret = inode->i_sb->dq_op->get_inode_usage(inode, &inode_usage); 20598c2ecf20Sopenharmony_ci if (ret) 20608c2ecf20Sopenharmony_ci return ret; 20618c2ecf20Sopenharmony_ci } 20628c2ecf20Sopenharmony_ci 20638c2ecf20Sopenharmony_ci /* Initialize the arrays */ 20648c2ecf20Sopenharmony_ci for (cnt = 0; cnt < MAXQUOTAS; cnt++) { 20658c2ecf20Sopenharmony_ci warn_to[cnt].w_type = QUOTA_NL_NOWARN; 20668c2ecf20Sopenharmony_ci warn_from_inodes[cnt].w_type = QUOTA_NL_NOWARN; 20678c2ecf20Sopenharmony_ci warn_from_space[cnt].w_type = QUOTA_NL_NOWARN; 20688c2ecf20Sopenharmony_ci } 20698c2ecf20Sopenharmony_ci 20708c2ecf20Sopenharmony_ci spin_lock(&dq_data_lock); 20718c2ecf20Sopenharmony_ci spin_lock(&inode->i_lock); 20728c2ecf20Sopenharmony_ci if (IS_NOQUOTA(inode)) { /* File without quota accounting? */ 20738c2ecf20Sopenharmony_ci spin_unlock(&inode->i_lock); 20748c2ecf20Sopenharmony_ci spin_unlock(&dq_data_lock); 20758c2ecf20Sopenharmony_ci return 0; 20768c2ecf20Sopenharmony_ci } 20778c2ecf20Sopenharmony_ci cur_space = __inode_get_bytes(inode); 20788c2ecf20Sopenharmony_ci rsv_space = __inode_get_rsv_space(inode); 20798c2ecf20Sopenharmony_ci /* 20808c2ecf20Sopenharmony_ci * Build the transfer_from list, check limits, and update usage in 20818c2ecf20Sopenharmony_ci * the target structures. 20828c2ecf20Sopenharmony_ci */ 20838c2ecf20Sopenharmony_ci for (cnt = 0; cnt < MAXQUOTAS; cnt++) { 20848c2ecf20Sopenharmony_ci /* 20858c2ecf20Sopenharmony_ci * Skip changes for same uid or gid or for turned off quota-type. 20868c2ecf20Sopenharmony_ci */ 20878c2ecf20Sopenharmony_ci if (!transfer_to[cnt]) 20888c2ecf20Sopenharmony_ci continue; 20898c2ecf20Sopenharmony_ci /* Avoid races with quotaoff() */ 20908c2ecf20Sopenharmony_ci if (!sb_has_quota_active(inode->i_sb, cnt)) 20918c2ecf20Sopenharmony_ci continue; 20928c2ecf20Sopenharmony_ci is_valid[cnt] = 1; 20938c2ecf20Sopenharmony_ci transfer_from[cnt] = i_dquot(inode)[cnt]; 20948c2ecf20Sopenharmony_ci ret = dquot_add_inodes(transfer_to[cnt], inode_usage, 20958c2ecf20Sopenharmony_ci &warn_to[cnt]); 20968c2ecf20Sopenharmony_ci if (ret) 20978c2ecf20Sopenharmony_ci goto over_quota; 20988c2ecf20Sopenharmony_ci ret = dquot_add_space(transfer_to[cnt], cur_space, rsv_space, 20998c2ecf20Sopenharmony_ci DQUOT_SPACE_WARN, &warn_to[cnt]); 21008c2ecf20Sopenharmony_ci if (ret) { 21018c2ecf20Sopenharmony_ci spin_lock(&transfer_to[cnt]->dq_dqb_lock); 21028c2ecf20Sopenharmony_ci dquot_decr_inodes(transfer_to[cnt], inode_usage); 21038c2ecf20Sopenharmony_ci spin_unlock(&transfer_to[cnt]->dq_dqb_lock); 21048c2ecf20Sopenharmony_ci goto over_quota; 21058c2ecf20Sopenharmony_ci } 21068c2ecf20Sopenharmony_ci } 21078c2ecf20Sopenharmony_ci 21088c2ecf20Sopenharmony_ci /* Decrease usage for source structures and update quota pointers */ 21098c2ecf20Sopenharmony_ci for (cnt = 0; cnt < MAXQUOTAS; cnt++) { 21108c2ecf20Sopenharmony_ci if (!is_valid[cnt]) 21118c2ecf20Sopenharmony_ci continue; 21128c2ecf20Sopenharmony_ci /* Due to IO error we might not have transfer_from[] structure */ 21138c2ecf20Sopenharmony_ci if (transfer_from[cnt]) { 21148c2ecf20Sopenharmony_ci int wtype; 21158c2ecf20Sopenharmony_ci 21168c2ecf20Sopenharmony_ci spin_lock(&transfer_from[cnt]->dq_dqb_lock); 21178c2ecf20Sopenharmony_ci wtype = info_idq_free(transfer_from[cnt], inode_usage); 21188c2ecf20Sopenharmony_ci if (wtype != QUOTA_NL_NOWARN) 21198c2ecf20Sopenharmony_ci prepare_warning(&warn_from_inodes[cnt], 21208c2ecf20Sopenharmony_ci transfer_from[cnt], wtype); 21218c2ecf20Sopenharmony_ci wtype = info_bdq_free(transfer_from[cnt], 21228c2ecf20Sopenharmony_ci cur_space + rsv_space); 21238c2ecf20Sopenharmony_ci if (wtype != QUOTA_NL_NOWARN) 21248c2ecf20Sopenharmony_ci prepare_warning(&warn_from_space[cnt], 21258c2ecf20Sopenharmony_ci transfer_from[cnt], wtype); 21268c2ecf20Sopenharmony_ci dquot_decr_inodes(transfer_from[cnt], inode_usage); 21278c2ecf20Sopenharmony_ci dquot_decr_space(transfer_from[cnt], cur_space); 21288c2ecf20Sopenharmony_ci dquot_free_reserved_space(transfer_from[cnt], 21298c2ecf20Sopenharmony_ci rsv_space); 21308c2ecf20Sopenharmony_ci spin_unlock(&transfer_from[cnt]->dq_dqb_lock); 21318c2ecf20Sopenharmony_ci } 21328c2ecf20Sopenharmony_ci i_dquot(inode)[cnt] = transfer_to[cnt]; 21338c2ecf20Sopenharmony_ci } 21348c2ecf20Sopenharmony_ci spin_unlock(&inode->i_lock); 21358c2ecf20Sopenharmony_ci spin_unlock(&dq_data_lock); 21368c2ecf20Sopenharmony_ci 21378c2ecf20Sopenharmony_ci /* 21388c2ecf20Sopenharmony_ci * These arrays are local and we hold dquot references so we don't need 21398c2ecf20Sopenharmony_ci * the srcu protection but still take dquot_srcu to avoid warning in 21408c2ecf20Sopenharmony_ci * mark_all_dquot_dirty(). 21418c2ecf20Sopenharmony_ci */ 21428c2ecf20Sopenharmony_ci index = srcu_read_lock(&dquot_srcu); 21438c2ecf20Sopenharmony_ci mark_all_dquot_dirty(transfer_from); 21448c2ecf20Sopenharmony_ci mark_all_dquot_dirty(transfer_to); 21458c2ecf20Sopenharmony_ci srcu_read_unlock(&dquot_srcu, index); 21468c2ecf20Sopenharmony_ci 21478c2ecf20Sopenharmony_ci flush_warnings(warn_to); 21488c2ecf20Sopenharmony_ci flush_warnings(warn_from_inodes); 21498c2ecf20Sopenharmony_ci flush_warnings(warn_from_space); 21508c2ecf20Sopenharmony_ci /* Pass back references to put */ 21518c2ecf20Sopenharmony_ci for (cnt = 0; cnt < MAXQUOTAS; cnt++) 21528c2ecf20Sopenharmony_ci if (is_valid[cnt]) 21538c2ecf20Sopenharmony_ci transfer_to[cnt] = transfer_from[cnt]; 21548c2ecf20Sopenharmony_ci return 0; 21558c2ecf20Sopenharmony_ciover_quota: 21568c2ecf20Sopenharmony_ci /* Back out changes we already did */ 21578c2ecf20Sopenharmony_ci for (cnt--; cnt >= 0; cnt--) { 21588c2ecf20Sopenharmony_ci if (!is_valid[cnt]) 21598c2ecf20Sopenharmony_ci continue; 21608c2ecf20Sopenharmony_ci spin_lock(&transfer_to[cnt]->dq_dqb_lock); 21618c2ecf20Sopenharmony_ci dquot_decr_inodes(transfer_to[cnt], inode_usage); 21628c2ecf20Sopenharmony_ci dquot_decr_space(transfer_to[cnt], cur_space); 21638c2ecf20Sopenharmony_ci dquot_free_reserved_space(transfer_to[cnt], rsv_space); 21648c2ecf20Sopenharmony_ci spin_unlock(&transfer_to[cnt]->dq_dqb_lock); 21658c2ecf20Sopenharmony_ci } 21668c2ecf20Sopenharmony_ci spin_unlock(&inode->i_lock); 21678c2ecf20Sopenharmony_ci spin_unlock(&dq_data_lock); 21688c2ecf20Sopenharmony_ci flush_warnings(warn_to); 21698c2ecf20Sopenharmony_ci return ret; 21708c2ecf20Sopenharmony_ci} 21718c2ecf20Sopenharmony_ciEXPORT_SYMBOL(__dquot_transfer); 21728c2ecf20Sopenharmony_ci 21738c2ecf20Sopenharmony_ci/* Wrapper for transferring ownership of an inode for uid/gid only 21748c2ecf20Sopenharmony_ci * Called from FSXXX_setattr() 21758c2ecf20Sopenharmony_ci */ 21768c2ecf20Sopenharmony_ciint dquot_transfer(struct inode *inode, struct iattr *iattr) 21778c2ecf20Sopenharmony_ci{ 21788c2ecf20Sopenharmony_ci struct dquot *transfer_to[MAXQUOTAS] = {}; 21798c2ecf20Sopenharmony_ci struct dquot *dquot; 21808c2ecf20Sopenharmony_ci struct super_block *sb = inode->i_sb; 21818c2ecf20Sopenharmony_ci int ret; 21828c2ecf20Sopenharmony_ci 21838c2ecf20Sopenharmony_ci if (!inode_quota_active(inode)) 21848c2ecf20Sopenharmony_ci return 0; 21858c2ecf20Sopenharmony_ci 21868c2ecf20Sopenharmony_ci if (iattr->ia_valid & ATTR_UID && !uid_eq(iattr->ia_uid, inode->i_uid)){ 21878c2ecf20Sopenharmony_ci dquot = dqget(sb, make_kqid_uid(iattr->ia_uid)); 21888c2ecf20Sopenharmony_ci if (IS_ERR(dquot)) { 21898c2ecf20Sopenharmony_ci if (PTR_ERR(dquot) != -ESRCH) { 21908c2ecf20Sopenharmony_ci ret = PTR_ERR(dquot); 21918c2ecf20Sopenharmony_ci goto out_put; 21928c2ecf20Sopenharmony_ci } 21938c2ecf20Sopenharmony_ci dquot = NULL; 21948c2ecf20Sopenharmony_ci } 21958c2ecf20Sopenharmony_ci transfer_to[USRQUOTA] = dquot; 21968c2ecf20Sopenharmony_ci } 21978c2ecf20Sopenharmony_ci if (iattr->ia_valid & ATTR_GID && !gid_eq(iattr->ia_gid, inode->i_gid)){ 21988c2ecf20Sopenharmony_ci dquot = dqget(sb, make_kqid_gid(iattr->ia_gid)); 21998c2ecf20Sopenharmony_ci if (IS_ERR(dquot)) { 22008c2ecf20Sopenharmony_ci if (PTR_ERR(dquot) != -ESRCH) { 22018c2ecf20Sopenharmony_ci ret = PTR_ERR(dquot); 22028c2ecf20Sopenharmony_ci goto out_put; 22038c2ecf20Sopenharmony_ci } 22048c2ecf20Sopenharmony_ci dquot = NULL; 22058c2ecf20Sopenharmony_ci } 22068c2ecf20Sopenharmony_ci transfer_to[GRPQUOTA] = dquot; 22078c2ecf20Sopenharmony_ci } 22088c2ecf20Sopenharmony_ci ret = __dquot_transfer(inode, transfer_to); 22098c2ecf20Sopenharmony_ciout_put: 22108c2ecf20Sopenharmony_ci dqput_all(transfer_to); 22118c2ecf20Sopenharmony_ci return ret; 22128c2ecf20Sopenharmony_ci} 22138c2ecf20Sopenharmony_ciEXPORT_SYMBOL(dquot_transfer); 22148c2ecf20Sopenharmony_ci 22158c2ecf20Sopenharmony_ci/* 22168c2ecf20Sopenharmony_ci * Write info of quota file to disk 22178c2ecf20Sopenharmony_ci */ 22188c2ecf20Sopenharmony_ciint dquot_commit_info(struct super_block *sb, int type) 22198c2ecf20Sopenharmony_ci{ 22208c2ecf20Sopenharmony_ci struct quota_info *dqopt = sb_dqopt(sb); 22218c2ecf20Sopenharmony_ci 22228c2ecf20Sopenharmony_ci return dqopt->ops[type]->write_file_info(sb, type); 22238c2ecf20Sopenharmony_ci} 22248c2ecf20Sopenharmony_ciEXPORT_SYMBOL(dquot_commit_info); 22258c2ecf20Sopenharmony_ci 22268c2ecf20Sopenharmony_ciint dquot_get_next_id(struct super_block *sb, struct kqid *qid) 22278c2ecf20Sopenharmony_ci{ 22288c2ecf20Sopenharmony_ci struct quota_info *dqopt = sb_dqopt(sb); 22298c2ecf20Sopenharmony_ci 22308c2ecf20Sopenharmony_ci if (!sb_has_quota_active(sb, qid->type)) 22318c2ecf20Sopenharmony_ci return -ESRCH; 22328c2ecf20Sopenharmony_ci if (!dqopt->ops[qid->type]->get_next_id) 22338c2ecf20Sopenharmony_ci return -ENOSYS; 22348c2ecf20Sopenharmony_ci return dqopt->ops[qid->type]->get_next_id(sb, qid); 22358c2ecf20Sopenharmony_ci} 22368c2ecf20Sopenharmony_ciEXPORT_SYMBOL(dquot_get_next_id); 22378c2ecf20Sopenharmony_ci 22388c2ecf20Sopenharmony_ci/* 22398c2ecf20Sopenharmony_ci * Definitions of diskquota operations. 22408c2ecf20Sopenharmony_ci */ 22418c2ecf20Sopenharmony_ciconst struct dquot_operations dquot_operations = { 22428c2ecf20Sopenharmony_ci .write_dquot = dquot_commit, 22438c2ecf20Sopenharmony_ci .acquire_dquot = dquot_acquire, 22448c2ecf20Sopenharmony_ci .release_dquot = dquot_release, 22458c2ecf20Sopenharmony_ci .mark_dirty = dquot_mark_dquot_dirty, 22468c2ecf20Sopenharmony_ci .write_info = dquot_commit_info, 22478c2ecf20Sopenharmony_ci .alloc_dquot = dquot_alloc, 22488c2ecf20Sopenharmony_ci .destroy_dquot = dquot_destroy, 22498c2ecf20Sopenharmony_ci .get_next_id = dquot_get_next_id, 22508c2ecf20Sopenharmony_ci}; 22518c2ecf20Sopenharmony_ciEXPORT_SYMBOL(dquot_operations); 22528c2ecf20Sopenharmony_ci 22538c2ecf20Sopenharmony_ci/* 22548c2ecf20Sopenharmony_ci * Generic helper for ->open on filesystems supporting disk quotas. 22558c2ecf20Sopenharmony_ci */ 22568c2ecf20Sopenharmony_ciint dquot_file_open(struct inode *inode, struct file *file) 22578c2ecf20Sopenharmony_ci{ 22588c2ecf20Sopenharmony_ci int error; 22598c2ecf20Sopenharmony_ci 22608c2ecf20Sopenharmony_ci error = generic_file_open(inode, file); 22618c2ecf20Sopenharmony_ci if (!error && (file->f_mode & FMODE_WRITE)) 22628c2ecf20Sopenharmony_ci error = dquot_initialize(inode); 22638c2ecf20Sopenharmony_ci return error; 22648c2ecf20Sopenharmony_ci} 22658c2ecf20Sopenharmony_ciEXPORT_SYMBOL(dquot_file_open); 22668c2ecf20Sopenharmony_ci 22678c2ecf20Sopenharmony_cistatic void vfs_cleanup_quota_inode(struct super_block *sb, int type) 22688c2ecf20Sopenharmony_ci{ 22698c2ecf20Sopenharmony_ci struct quota_info *dqopt = sb_dqopt(sb); 22708c2ecf20Sopenharmony_ci struct inode *inode = dqopt->files[type]; 22718c2ecf20Sopenharmony_ci 22728c2ecf20Sopenharmony_ci if (!inode) 22738c2ecf20Sopenharmony_ci return; 22748c2ecf20Sopenharmony_ci if (!(dqopt->flags & DQUOT_QUOTA_SYS_FILE)) { 22758c2ecf20Sopenharmony_ci inode_lock(inode); 22768c2ecf20Sopenharmony_ci inode->i_flags &= ~S_NOQUOTA; 22778c2ecf20Sopenharmony_ci inode_unlock(inode); 22788c2ecf20Sopenharmony_ci } 22798c2ecf20Sopenharmony_ci dqopt->files[type] = NULL; 22808c2ecf20Sopenharmony_ci iput(inode); 22818c2ecf20Sopenharmony_ci} 22828c2ecf20Sopenharmony_ci 22838c2ecf20Sopenharmony_ci/* 22848c2ecf20Sopenharmony_ci * Turn quota off on a device. type == -1 ==> quotaoff for all types (umount) 22858c2ecf20Sopenharmony_ci */ 22868c2ecf20Sopenharmony_ciint dquot_disable(struct super_block *sb, int type, unsigned int flags) 22878c2ecf20Sopenharmony_ci{ 22888c2ecf20Sopenharmony_ci int cnt; 22898c2ecf20Sopenharmony_ci struct quota_info *dqopt = sb_dqopt(sb); 22908c2ecf20Sopenharmony_ci 22918c2ecf20Sopenharmony_ci /* s_umount should be held in exclusive mode */ 22928c2ecf20Sopenharmony_ci if (WARN_ON_ONCE(down_read_trylock(&sb->s_umount))) 22938c2ecf20Sopenharmony_ci up_read(&sb->s_umount); 22948c2ecf20Sopenharmony_ci 22958c2ecf20Sopenharmony_ci /* Cannot turn off usage accounting without turning off limits, or 22968c2ecf20Sopenharmony_ci * suspend quotas and simultaneously turn quotas off. */ 22978c2ecf20Sopenharmony_ci if ((flags & DQUOT_USAGE_ENABLED && !(flags & DQUOT_LIMITS_ENABLED)) 22988c2ecf20Sopenharmony_ci || (flags & DQUOT_SUSPENDED && flags & (DQUOT_LIMITS_ENABLED | 22998c2ecf20Sopenharmony_ci DQUOT_USAGE_ENABLED))) 23008c2ecf20Sopenharmony_ci return -EINVAL; 23018c2ecf20Sopenharmony_ci 23028c2ecf20Sopenharmony_ci /* 23038c2ecf20Sopenharmony_ci * Skip everything if there's nothing to do. We have to do this because 23048c2ecf20Sopenharmony_ci * sometimes we are called when fill_super() failed and calling 23058c2ecf20Sopenharmony_ci * sync_fs() in such cases does no good. 23068c2ecf20Sopenharmony_ci */ 23078c2ecf20Sopenharmony_ci if (!sb_any_quota_loaded(sb)) 23088c2ecf20Sopenharmony_ci return 0; 23098c2ecf20Sopenharmony_ci 23108c2ecf20Sopenharmony_ci for (cnt = 0; cnt < MAXQUOTAS; cnt++) { 23118c2ecf20Sopenharmony_ci if (type != -1 && cnt != type) 23128c2ecf20Sopenharmony_ci continue; 23138c2ecf20Sopenharmony_ci if (!sb_has_quota_loaded(sb, cnt)) 23148c2ecf20Sopenharmony_ci continue; 23158c2ecf20Sopenharmony_ci 23168c2ecf20Sopenharmony_ci if (flags & DQUOT_SUSPENDED) { 23178c2ecf20Sopenharmony_ci spin_lock(&dq_state_lock); 23188c2ecf20Sopenharmony_ci dqopt->flags |= 23198c2ecf20Sopenharmony_ci dquot_state_flag(DQUOT_SUSPENDED, cnt); 23208c2ecf20Sopenharmony_ci spin_unlock(&dq_state_lock); 23218c2ecf20Sopenharmony_ci } else { 23228c2ecf20Sopenharmony_ci spin_lock(&dq_state_lock); 23238c2ecf20Sopenharmony_ci dqopt->flags &= ~dquot_state_flag(flags, cnt); 23248c2ecf20Sopenharmony_ci /* Turning off suspended quotas? */ 23258c2ecf20Sopenharmony_ci if (!sb_has_quota_loaded(sb, cnt) && 23268c2ecf20Sopenharmony_ci sb_has_quota_suspended(sb, cnt)) { 23278c2ecf20Sopenharmony_ci dqopt->flags &= ~dquot_state_flag( 23288c2ecf20Sopenharmony_ci DQUOT_SUSPENDED, cnt); 23298c2ecf20Sopenharmony_ci spin_unlock(&dq_state_lock); 23308c2ecf20Sopenharmony_ci vfs_cleanup_quota_inode(sb, cnt); 23318c2ecf20Sopenharmony_ci continue; 23328c2ecf20Sopenharmony_ci } 23338c2ecf20Sopenharmony_ci spin_unlock(&dq_state_lock); 23348c2ecf20Sopenharmony_ci } 23358c2ecf20Sopenharmony_ci 23368c2ecf20Sopenharmony_ci /* We still have to keep quota loaded? */ 23378c2ecf20Sopenharmony_ci if (sb_has_quota_loaded(sb, cnt) && !(flags & DQUOT_SUSPENDED)) 23388c2ecf20Sopenharmony_ci continue; 23398c2ecf20Sopenharmony_ci 23408c2ecf20Sopenharmony_ci /* Note: these are blocking operations */ 23418c2ecf20Sopenharmony_ci drop_dquot_ref(sb, cnt); 23428c2ecf20Sopenharmony_ci invalidate_dquots(sb, cnt); 23438c2ecf20Sopenharmony_ci /* 23448c2ecf20Sopenharmony_ci * Now all dquots should be invalidated, all writes done so we 23458c2ecf20Sopenharmony_ci * should be only users of the info. No locks needed. 23468c2ecf20Sopenharmony_ci */ 23478c2ecf20Sopenharmony_ci if (info_dirty(&dqopt->info[cnt])) 23488c2ecf20Sopenharmony_ci sb->dq_op->write_info(sb, cnt); 23498c2ecf20Sopenharmony_ci if (dqopt->ops[cnt]->free_file_info) 23508c2ecf20Sopenharmony_ci dqopt->ops[cnt]->free_file_info(sb, cnt); 23518c2ecf20Sopenharmony_ci put_quota_format(dqopt->info[cnt].dqi_format); 23528c2ecf20Sopenharmony_ci dqopt->info[cnt].dqi_flags = 0; 23538c2ecf20Sopenharmony_ci dqopt->info[cnt].dqi_igrace = 0; 23548c2ecf20Sopenharmony_ci dqopt->info[cnt].dqi_bgrace = 0; 23558c2ecf20Sopenharmony_ci dqopt->ops[cnt] = NULL; 23568c2ecf20Sopenharmony_ci } 23578c2ecf20Sopenharmony_ci 23588c2ecf20Sopenharmony_ci /* Skip syncing and setting flags if quota files are hidden */ 23598c2ecf20Sopenharmony_ci if (dqopt->flags & DQUOT_QUOTA_SYS_FILE) 23608c2ecf20Sopenharmony_ci goto put_inodes; 23618c2ecf20Sopenharmony_ci 23628c2ecf20Sopenharmony_ci /* Sync the superblock so that buffers with quota data are written to 23638c2ecf20Sopenharmony_ci * disk (and so userspace sees correct data afterwards). */ 23648c2ecf20Sopenharmony_ci if (sb->s_op->sync_fs) 23658c2ecf20Sopenharmony_ci sb->s_op->sync_fs(sb, 1); 23668c2ecf20Sopenharmony_ci sync_blockdev(sb->s_bdev); 23678c2ecf20Sopenharmony_ci /* Now the quota files are just ordinary files and we can set the 23688c2ecf20Sopenharmony_ci * inode flags back. Moreover we discard the pagecache so that 23698c2ecf20Sopenharmony_ci * userspace sees the writes we did bypassing the pagecache. We 23708c2ecf20Sopenharmony_ci * must also discard the blockdev buffers so that we see the 23718c2ecf20Sopenharmony_ci * changes done by userspace on the next quotaon() */ 23728c2ecf20Sopenharmony_ci for (cnt = 0; cnt < MAXQUOTAS; cnt++) 23738c2ecf20Sopenharmony_ci if (!sb_has_quota_loaded(sb, cnt) && dqopt->files[cnt]) { 23748c2ecf20Sopenharmony_ci inode_lock(dqopt->files[cnt]); 23758c2ecf20Sopenharmony_ci truncate_inode_pages(&dqopt->files[cnt]->i_data, 0); 23768c2ecf20Sopenharmony_ci inode_unlock(dqopt->files[cnt]); 23778c2ecf20Sopenharmony_ci } 23788c2ecf20Sopenharmony_ci if (sb->s_bdev) 23798c2ecf20Sopenharmony_ci invalidate_bdev(sb->s_bdev); 23808c2ecf20Sopenharmony_ciput_inodes: 23818c2ecf20Sopenharmony_ci /* We are done when suspending quotas */ 23828c2ecf20Sopenharmony_ci if (flags & DQUOT_SUSPENDED) 23838c2ecf20Sopenharmony_ci return 0; 23848c2ecf20Sopenharmony_ci 23858c2ecf20Sopenharmony_ci for (cnt = 0; cnt < MAXQUOTAS; cnt++) 23868c2ecf20Sopenharmony_ci if (!sb_has_quota_loaded(sb, cnt)) 23878c2ecf20Sopenharmony_ci vfs_cleanup_quota_inode(sb, cnt); 23888c2ecf20Sopenharmony_ci return 0; 23898c2ecf20Sopenharmony_ci} 23908c2ecf20Sopenharmony_ciEXPORT_SYMBOL(dquot_disable); 23918c2ecf20Sopenharmony_ci 23928c2ecf20Sopenharmony_ciint dquot_quota_off(struct super_block *sb, int type) 23938c2ecf20Sopenharmony_ci{ 23948c2ecf20Sopenharmony_ci return dquot_disable(sb, type, 23958c2ecf20Sopenharmony_ci DQUOT_USAGE_ENABLED | DQUOT_LIMITS_ENABLED); 23968c2ecf20Sopenharmony_ci} 23978c2ecf20Sopenharmony_ciEXPORT_SYMBOL(dquot_quota_off); 23988c2ecf20Sopenharmony_ci 23998c2ecf20Sopenharmony_ci/* 24008c2ecf20Sopenharmony_ci * Turn quotas on on a device 24018c2ecf20Sopenharmony_ci */ 24028c2ecf20Sopenharmony_ci 24038c2ecf20Sopenharmony_cistatic int vfs_setup_quota_inode(struct inode *inode, int type) 24048c2ecf20Sopenharmony_ci{ 24058c2ecf20Sopenharmony_ci struct super_block *sb = inode->i_sb; 24068c2ecf20Sopenharmony_ci struct quota_info *dqopt = sb_dqopt(sb); 24078c2ecf20Sopenharmony_ci 24088c2ecf20Sopenharmony_ci if (is_bad_inode(inode)) 24098c2ecf20Sopenharmony_ci return -EUCLEAN; 24108c2ecf20Sopenharmony_ci if (!S_ISREG(inode->i_mode)) 24118c2ecf20Sopenharmony_ci return -EACCES; 24128c2ecf20Sopenharmony_ci if (IS_RDONLY(inode)) 24138c2ecf20Sopenharmony_ci return -EROFS; 24148c2ecf20Sopenharmony_ci if (sb_has_quota_loaded(sb, type)) 24158c2ecf20Sopenharmony_ci return -EBUSY; 24168c2ecf20Sopenharmony_ci 24178c2ecf20Sopenharmony_ci /* 24188c2ecf20Sopenharmony_ci * Quota files should never be encrypted. They should be thought of as 24198c2ecf20Sopenharmony_ci * filesystem metadata, not user data. New-style internal quota files 24208c2ecf20Sopenharmony_ci * cannot be encrypted by users anyway, but old-style external quota 24218c2ecf20Sopenharmony_ci * files could potentially be incorrectly created in an encrypted 24228c2ecf20Sopenharmony_ci * directory, hence this explicit check. Some reasons why encrypted 24238c2ecf20Sopenharmony_ci * quota files don't work include: (1) some filesystems that support 24248c2ecf20Sopenharmony_ci * encryption don't handle it in their quota_read and quota_write, and 24258c2ecf20Sopenharmony_ci * (2) cleaning up encrypted quota files at unmount would need special 24268c2ecf20Sopenharmony_ci * consideration, as quota files are cleaned up later than user files. 24278c2ecf20Sopenharmony_ci */ 24288c2ecf20Sopenharmony_ci if (IS_ENCRYPTED(inode)) 24298c2ecf20Sopenharmony_ci return -EINVAL; 24308c2ecf20Sopenharmony_ci 24318c2ecf20Sopenharmony_ci dqopt->files[type] = igrab(inode); 24328c2ecf20Sopenharmony_ci if (!dqopt->files[type]) 24338c2ecf20Sopenharmony_ci return -EIO; 24348c2ecf20Sopenharmony_ci if (!(dqopt->flags & DQUOT_QUOTA_SYS_FILE)) { 24358c2ecf20Sopenharmony_ci /* We don't want quota and atime on quota files (deadlocks 24368c2ecf20Sopenharmony_ci * possible) Also nobody should write to the file - we use 24378c2ecf20Sopenharmony_ci * special IO operations which ignore the immutable bit. */ 24388c2ecf20Sopenharmony_ci inode_lock(inode); 24398c2ecf20Sopenharmony_ci inode->i_flags |= S_NOQUOTA; 24408c2ecf20Sopenharmony_ci inode_unlock(inode); 24418c2ecf20Sopenharmony_ci /* 24428c2ecf20Sopenharmony_ci * When S_NOQUOTA is set, remove dquot references as no more 24438c2ecf20Sopenharmony_ci * references can be added 24448c2ecf20Sopenharmony_ci */ 24458c2ecf20Sopenharmony_ci __dquot_drop(inode); 24468c2ecf20Sopenharmony_ci } 24478c2ecf20Sopenharmony_ci return 0; 24488c2ecf20Sopenharmony_ci} 24498c2ecf20Sopenharmony_ci 24508c2ecf20Sopenharmony_ciint dquot_load_quota_sb(struct super_block *sb, int type, int format_id, 24518c2ecf20Sopenharmony_ci unsigned int flags) 24528c2ecf20Sopenharmony_ci{ 24538c2ecf20Sopenharmony_ci struct quota_format_type *fmt = find_quota_format(format_id); 24548c2ecf20Sopenharmony_ci struct quota_info *dqopt = sb_dqopt(sb); 24558c2ecf20Sopenharmony_ci int error; 24568c2ecf20Sopenharmony_ci 24578c2ecf20Sopenharmony_ci /* Just unsuspend quotas? */ 24588c2ecf20Sopenharmony_ci BUG_ON(flags & DQUOT_SUSPENDED); 24598c2ecf20Sopenharmony_ci /* s_umount should be held in exclusive mode */ 24608c2ecf20Sopenharmony_ci if (WARN_ON_ONCE(down_read_trylock(&sb->s_umount))) 24618c2ecf20Sopenharmony_ci up_read(&sb->s_umount); 24628c2ecf20Sopenharmony_ci 24638c2ecf20Sopenharmony_ci if (!fmt) 24648c2ecf20Sopenharmony_ci return -ESRCH; 24658c2ecf20Sopenharmony_ci if (!sb->s_op->quota_write || !sb->s_op->quota_read || 24668c2ecf20Sopenharmony_ci (type == PRJQUOTA && sb->dq_op->get_projid == NULL)) { 24678c2ecf20Sopenharmony_ci error = -EINVAL; 24688c2ecf20Sopenharmony_ci goto out_fmt; 24698c2ecf20Sopenharmony_ci } 24708c2ecf20Sopenharmony_ci /* Filesystems outside of init_user_ns not yet supported */ 24718c2ecf20Sopenharmony_ci if (sb->s_user_ns != &init_user_ns) { 24728c2ecf20Sopenharmony_ci error = -EINVAL; 24738c2ecf20Sopenharmony_ci goto out_fmt; 24748c2ecf20Sopenharmony_ci } 24758c2ecf20Sopenharmony_ci /* Usage always has to be set... */ 24768c2ecf20Sopenharmony_ci if (!(flags & DQUOT_USAGE_ENABLED)) { 24778c2ecf20Sopenharmony_ci error = -EINVAL; 24788c2ecf20Sopenharmony_ci goto out_fmt; 24798c2ecf20Sopenharmony_ci } 24808c2ecf20Sopenharmony_ci if (sb_has_quota_loaded(sb, type)) { 24818c2ecf20Sopenharmony_ci error = -EBUSY; 24828c2ecf20Sopenharmony_ci goto out_fmt; 24838c2ecf20Sopenharmony_ci } 24848c2ecf20Sopenharmony_ci 24858c2ecf20Sopenharmony_ci if (!(dqopt->flags & DQUOT_QUOTA_SYS_FILE)) { 24868c2ecf20Sopenharmony_ci /* As we bypass the pagecache we must now flush all the 24878c2ecf20Sopenharmony_ci * dirty data and invalidate caches so that kernel sees 24888c2ecf20Sopenharmony_ci * changes from userspace. It is not enough to just flush 24898c2ecf20Sopenharmony_ci * the quota file since if blocksize < pagesize, invalidation 24908c2ecf20Sopenharmony_ci * of the cache could fail because of other unrelated dirty 24918c2ecf20Sopenharmony_ci * data */ 24928c2ecf20Sopenharmony_ci sync_filesystem(sb); 24938c2ecf20Sopenharmony_ci invalidate_bdev(sb->s_bdev); 24948c2ecf20Sopenharmony_ci } 24958c2ecf20Sopenharmony_ci 24968c2ecf20Sopenharmony_ci error = -EINVAL; 24978c2ecf20Sopenharmony_ci if (!fmt->qf_ops->check_quota_file(sb, type)) 24988c2ecf20Sopenharmony_ci goto out_fmt; 24998c2ecf20Sopenharmony_ci 25008c2ecf20Sopenharmony_ci dqopt->ops[type] = fmt->qf_ops; 25018c2ecf20Sopenharmony_ci dqopt->info[type].dqi_format = fmt; 25028c2ecf20Sopenharmony_ci dqopt->info[type].dqi_fmt_id = format_id; 25038c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&dqopt->info[type].dqi_dirty_list); 25048c2ecf20Sopenharmony_ci error = dqopt->ops[type]->read_file_info(sb, type); 25058c2ecf20Sopenharmony_ci if (error < 0) 25068c2ecf20Sopenharmony_ci goto out_fmt; 25078c2ecf20Sopenharmony_ci if (dqopt->flags & DQUOT_QUOTA_SYS_FILE) { 25088c2ecf20Sopenharmony_ci spin_lock(&dq_data_lock); 25098c2ecf20Sopenharmony_ci dqopt->info[type].dqi_flags |= DQF_SYS_FILE; 25108c2ecf20Sopenharmony_ci spin_unlock(&dq_data_lock); 25118c2ecf20Sopenharmony_ci } 25128c2ecf20Sopenharmony_ci spin_lock(&dq_state_lock); 25138c2ecf20Sopenharmony_ci dqopt->flags |= dquot_state_flag(flags, type); 25148c2ecf20Sopenharmony_ci spin_unlock(&dq_state_lock); 25158c2ecf20Sopenharmony_ci 25168c2ecf20Sopenharmony_ci error = add_dquot_ref(sb, type); 25178c2ecf20Sopenharmony_ci if (error) 25188c2ecf20Sopenharmony_ci dquot_disable(sb, type, 25198c2ecf20Sopenharmony_ci DQUOT_USAGE_ENABLED | DQUOT_LIMITS_ENABLED); 25208c2ecf20Sopenharmony_ci 25218c2ecf20Sopenharmony_ci return error; 25228c2ecf20Sopenharmony_ciout_fmt: 25238c2ecf20Sopenharmony_ci put_quota_format(fmt); 25248c2ecf20Sopenharmony_ci 25258c2ecf20Sopenharmony_ci return error; 25268c2ecf20Sopenharmony_ci} 25278c2ecf20Sopenharmony_ciEXPORT_SYMBOL(dquot_load_quota_sb); 25288c2ecf20Sopenharmony_ci 25298c2ecf20Sopenharmony_ci/* 25308c2ecf20Sopenharmony_ci * More powerful function for turning on quotas on given quota inode allowing 25318c2ecf20Sopenharmony_ci * setting of individual quota flags 25328c2ecf20Sopenharmony_ci */ 25338c2ecf20Sopenharmony_ciint dquot_load_quota_inode(struct inode *inode, int type, int format_id, 25348c2ecf20Sopenharmony_ci unsigned int flags) 25358c2ecf20Sopenharmony_ci{ 25368c2ecf20Sopenharmony_ci int err; 25378c2ecf20Sopenharmony_ci 25388c2ecf20Sopenharmony_ci err = vfs_setup_quota_inode(inode, type); 25398c2ecf20Sopenharmony_ci if (err < 0) 25408c2ecf20Sopenharmony_ci return err; 25418c2ecf20Sopenharmony_ci err = dquot_load_quota_sb(inode->i_sb, type, format_id, flags); 25428c2ecf20Sopenharmony_ci if (err < 0) 25438c2ecf20Sopenharmony_ci vfs_cleanup_quota_inode(inode->i_sb, type); 25448c2ecf20Sopenharmony_ci return err; 25458c2ecf20Sopenharmony_ci} 25468c2ecf20Sopenharmony_ciEXPORT_SYMBOL(dquot_load_quota_inode); 25478c2ecf20Sopenharmony_ci 25488c2ecf20Sopenharmony_ci/* Reenable quotas on remount RW */ 25498c2ecf20Sopenharmony_ciint dquot_resume(struct super_block *sb, int type) 25508c2ecf20Sopenharmony_ci{ 25518c2ecf20Sopenharmony_ci struct quota_info *dqopt = sb_dqopt(sb); 25528c2ecf20Sopenharmony_ci int ret = 0, cnt; 25538c2ecf20Sopenharmony_ci unsigned int flags; 25548c2ecf20Sopenharmony_ci 25558c2ecf20Sopenharmony_ci /* s_umount should be held in exclusive mode */ 25568c2ecf20Sopenharmony_ci if (WARN_ON_ONCE(down_read_trylock(&sb->s_umount))) 25578c2ecf20Sopenharmony_ci up_read(&sb->s_umount); 25588c2ecf20Sopenharmony_ci 25598c2ecf20Sopenharmony_ci for (cnt = 0; cnt < MAXQUOTAS; cnt++) { 25608c2ecf20Sopenharmony_ci if (type != -1 && cnt != type) 25618c2ecf20Sopenharmony_ci continue; 25628c2ecf20Sopenharmony_ci if (!sb_has_quota_suspended(sb, cnt)) 25638c2ecf20Sopenharmony_ci continue; 25648c2ecf20Sopenharmony_ci 25658c2ecf20Sopenharmony_ci spin_lock(&dq_state_lock); 25668c2ecf20Sopenharmony_ci flags = dqopt->flags & dquot_state_flag(DQUOT_USAGE_ENABLED | 25678c2ecf20Sopenharmony_ci DQUOT_LIMITS_ENABLED, 25688c2ecf20Sopenharmony_ci cnt); 25698c2ecf20Sopenharmony_ci dqopt->flags &= ~dquot_state_flag(DQUOT_STATE_FLAGS, cnt); 25708c2ecf20Sopenharmony_ci spin_unlock(&dq_state_lock); 25718c2ecf20Sopenharmony_ci 25728c2ecf20Sopenharmony_ci flags = dquot_generic_flag(flags, cnt); 25738c2ecf20Sopenharmony_ci ret = dquot_load_quota_sb(sb, cnt, dqopt->info[cnt].dqi_fmt_id, 25748c2ecf20Sopenharmony_ci flags); 25758c2ecf20Sopenharmony_ci if (ret < 0) 25768c2ecf20Sopenharmony_ci vfs_cleanup_quota_inode(sb, cnt); 25778c2ecf20Sopenharmony_ci } 25788c2ecf20Sopenharmony_ci 25798c2ecf20Sopenharmony_ci return ret; 25808c2ecf20Sopenharmony_ci} 25818c2ecf20Sopenharmony_ciEXPORT_SYMBOL(dquot_resume); 25828c2ecf20Sopenharmony_ci 25838c2ecf20Sopenharmony_ciint dquot_quota_on(struct super_block *sb, int type, int format_id, 25848c2ecf20Sopenharmony_ci const struct path *path) 25858c2ecf20Sopenharmony_ci{ 25868c2ecf20Sopenharmony_ci int error = security_quota_on(path->dentry); 25878c2ecf20Sopenharmony_ci if (error) 25888c2ecf20Sopenharmony_ci return error; 25898c2ecf20Sopenharmony_ci /* Quota file not on the same filesystem? */ 25908c2ecf20Sopenharmony_ci if (path->dentry->d_sb != sb) 25918c2ecf20Sopenharmony_ci error = -EXDEV; 25928c2ecf20Sopenharmony_ci else 25938c2ecf20Sopenharmony_ci error = dquot_load_quota_inode(d_inode(path->dentry), type, 25948c2ecf20Sopenharmony_ci format_id, DQUOT_USAGE_ENABLED | 25958c2ecf20Sopenharmony_ci DQUOT_LIMITS_ENABLED); 25968c2ecf20Sopenharmony_ci return error; 25978c2ecf20Sopenharmony_ci} 25988c2ecf20Sopenharmony_ciEXPORT_SYMBOL(dquot_quota_on); 25998c2ecf20Sopenharmony_ci 26008c2ecf20Sopenharmony_ci/* 26018c2ecf20Sopenharmony_ci * This function is used when filesystem needs to initialize quotas 26028c2ecf20Sopenharmony_ci * during mount time. 26038c2ecf20Sopenharmony_ci */ 26048c2ecf20Sopenharmony_ciint dquot_quota_on_mount(struct super_block *sb, char *qf_name, 26058c2ecf20Sopenharmony_ci int format_id, int type) 26068c2ecf20Sopenharmony_ci{ 26078c2ecf20Sopenharmony_ci struct dentry *dentry; 26088c2ecf20Sopenharmony_ci int error; 26098c2ecf20Sopenharmony_ci 26108c2ecf20Sopenharmony_ci dentry = lookup_positive_unlocked(qf_name, sb->s_root, strlen(qf_name)); 26118c2ecf20Sopenharmony_ci if (IS_ERR(dentry)) 26128c2ecf20Sopenharmony_ci return PTR_ERR(dentry); 26138c2ecf20Sopenharmony_ci 26148c2ecf20Sopenharmony_ci error = security_quota_on(dentry); 26158c2ecf20Sopenharmony_ci if (!error) 26168c2ecf20Sopenharmony_ci error = dquot_load_quota_inode(d_inode(dentry), type, format_id, 26178c2ecf20Sopenharmony_ci DQUOT_USAGE_ENABLED | DQUOT_LIMITS_ENABLED); 26188c2ecf20Sopenharmony_ci 26198c2ecf20Sopenharmony_ci dput(dentry); 26208c2ecf20Sopenharmony_ci return error; 26218c2ecf20Sopenharmony_ci} 26228c2ecf20Sopenharmony_ciEXPORT_SYMBOL(dquot_quota_on_mount); 26238c2ecf20Sopenharmony_ci 26248c2ecf20Sopenharmony_cistatic int dquot_quota_enable(struct super_block *sb, unsigned int flags) 26258c2ecf20Sopenharmony_ci{ 26268c2ecf20Sopenharmony_ci int ret; 26278c2ecf20Sopenharmony_ci int type; 26288c2ecf20Sopenharmony_ci struct quota_info *dqopt = sb_dqopt(sb); 26298c2ecf20Sopenharmony_ci 26308c2ecf20Sopenharmony_ci if (!(dqopt->flags & DQUOT_QUOTA_SYS_FILE)) 26318c2ecf20Sopenharmony_ci return -ENOSYS; 26328c2ecf20Sopenharmony_ci /* Accounting cannot be turned on while fs is mounted */ 26338c2ecf20Sopenharmony_ci flags &= ~(FS_QUOTA_UDQ_ACCT | FS_QUOTA_GDQ_ACCT | FS_QUOTA_PDQ_ACCT); 26348c2ecf20Sopenharmony_ci if (!flags) 26358c2ecf20Sopenharmony_ci return -EINVAL; 26368c2ecf20Sopenharmony_ci for (type = 0; type < MAXQUOTAS; type++) { 26378c2ecf20Sopenharmony_ci if (!(flags & qtype_enforce_flag(type))) 26388c2ecf20Sopenharmony_ci continue; 26398c2ecf20Sopenharmony_ci /* Can't enforce without accounting */ 26408c2ecf20Sopenharmony_ci if (!sb_has_quota_usage_enabled(sb, type)) { 26418c2ecf20Sopenharmony_ci ret = -EINVAL; 26428c2ecf20Sopenharmony_ci goto out_err; 26438c2ecf20Sopenharmony_ci } 26448c2ecf20Sopenharmony_ci if (sb_has_quota_limits_enabled(sb, type)) { 26458c2ecf20Sopenharmony_ci ret = -EBUSY; 26468c2ecf20Sopenharmony_ci goto out_err; 26478c2ecf20Sopenharmony_ci } 26488c2ecf20Sopenharmony_ci spin_lock(&dq_state_lock); 26498c2ecf20Sopenharmony_ci dqopt->flags |= dquot_state_flag(DQUOT_LIMITS_ENABLED, type); 26508c2ecf20Sopenharmony_ci spin_unlock(&dq_state_lock); 26518c2ecf20Sopenharmony_ci } 26528c2ecf20Sopenharmony_ci return 0; 26538c2ecf20Sopenharmony_ciout_err: 26548c2ecf20Sopenharmony_ci /* Backout enforcement enablement we already did */ 26558c2ecf20Sopenharmony_ci for (type--; type >= 0; type--) { 26568c2ecf20Sopenharmony_ci if (flags & qtype_enforce_flag(type)) 26578c2ecf20Sopenharmony_ci dquot_disable(sb, type, DQUOT_LIMITS_ENABLED); 26588c2ecf20Sopenharmony_ci } 26598c2ecf20Sopenharmony_ci /* Error code translation for better compatibility with XFS */ 26608c2ecf20Sopenharmony_ci if (ret == -EBUSY) 26618c2ecf20Sopenharmony_ci ret = -EEXIST; 26628c2ecf20Sopenharmony_ci return ret; 26638c2ecf20Sopenharmony_ci} 26648c2ecf20Sopenharmony_ci 26658c2ecf20Sopenharmony_cistatic int dquot_quota_disable(struct super_block *sb, unsigned int flags) 26668c2ecf20Sopenharmony_ci{ 26678c2ecf20Sopenharmony_ci int ret; 26688c2ecf20Sopenharmony_ci int type; 26698c2ecf20Sopenharmony_ci struct quota_info *dqopt = sb_dqopt(sb); 26708c2ecf20Sopenharmony_ci 26718c2ecf20Sopenharmony_ci if (!(dqopt->flags & DQUOT_QUOTA_SYS_FILE)) 26728c2ecf20Sopenharmony_ci return -ENOSYS; 26738c2ecf20Sopenharmony_ci /* 26748c2ecf20Sopenharmony_ci * We don't support turning off accounting via quotactl. In principle 26758c2ecf20Sopenharmony_ci * quota infrastructure can do this but filesystems don't expect 26768c2ecf20Sopenharmony_ci * userspace to be able to do it. 26778c2ecf20Sopenharmony_ci */ 26788c2ecf20Sopenharmony_ci if (flags & 26798c2ecf20Sopenharmony_ci (FS_QUOTA_UDQ_ACCT | FS_QUOTA_GDQ_ACCT | FS_QUOTA_PDQ_ACCT)) 26808c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 26818c2ecf20Sopenharmony_ci 26828c2ecf20Sopenharmony_ci /* Filter out limits not enabled */ 26838c2ecf20Sopenharmony_ci for (type = 0; type < MAXQUOTAS; type++) 26848c2ecf20Sopenharmony_ci if (!sb_has_quota_limits_enabled(sb, type)) 26858c2ecf20Sopenharmony_ci flags &= ~qtype_enforce_flag(type); 26868c2ecf20Sopenharmony_ci /* Nothing left? */ 26878c2ecf20Sopenharmony_ci if (!flags) 26888c2ecf20Sopenharmony_ci return -EEXIST; 26898c2ecf20Sopenharmony_ci for (type = 0; type < MAXQUOTAS; type++) { 26908c2ecf20Sopenharmony_ci if (flags & qtype_enforce_flag(type)) { 26918c2ecf20Sopenharmony_ci ret = dquot_disable(sb, type, DQUOT_LIMITS_ENABLED); 26928c2ecf20Sopenharmony_ci if (ret < 0) 26938c2ecf20Sopenharmony_ci goto out_err; 26948c2ecf20Sopenharmony_ci } 26958c2ecf20Sopenharmony_ci } 26968c2ecf20Sopenharmony_ci return 0; 26978c2ecf20Sopenharmony_ciout_err: 26988c2ecf20Sopenharmony_ci /* Backout enforcement disabling we already did */ 26998c2ecf20Sopenharmony_ci for (type--; type >= 0; type--) { 27008c2ecf20Sopenharmony_ci if (flags & qtype_enforce_flag(type)) { 27018c2ecf20Sopenharmony_ci spin_lock(&dq_state_lock); 27028c2ecf20Sopenharmony_ci dqopt->flags |= 27038c2ecf20Sopenharmony_ci dquot_state_flag(DQUOT_LIMITS_ENABLED, type); 27048c2ecf20Sopenharmony_ci spin_unlock(&dq_state_lock); 27058c2ecf20Sopenharmony_ci } 27068c2ecf20Sopenharmony_ci } 27078c2ecf20Sopenharmony_ci return ret; 27088c2ecf20Sopenharmony_ci} 27098c2ecf20Sopenharmony_ci 27108c2ecf20Sopenharmony_ci/* Generic routine for getting common part of quota structure */ 27118c2ecf20Sopenharmony_cistatic void do_get_dqblk(struct dquot *dquot, struct qc_dqblk *di) 27128c2ecf20Sopenharmony_ci{ 27138c2ecf20Sopenharmony_ci struct mem_dqblk *dm = &dquot->dq_dqb; 27148c2ecf20Sopenharmony_ci 27158c2ecf20Sopenharmony_ci memset(di, 0, sizeof(*di)); 27168c2ecf20Sopenharmony_ci spin_lock(&dquot->dq_dqb_lock); 27178c2ecf20Sopenharmony_ci di->d_spc_hardlimit = dm->dqb_bhardlimit; 27188c2ecf20Sopenharmony_ci di->d_spc_softlimit = dm->dqb_bsoftlimit; 27198c2ecf20Sopenharmony_ci di->d_ino_hardlimit = dm->dqb_ihardlimit; 27208c2ecf20Sopenharmony_ci di->d_ino_softlimit = dm->dqb_isoftlimit; 27218c2ecf20Sopenharmony_ci di->d_space = dm->dqb_curspace + dm->dqb_rsvspace; 27228c2ecf20Sopenharmony_ci di->d_ino_count = dm->dqb_curinodes; 27238c2ecf20Sopenharmony_ci di->d_spc_timer = dm->dqb_btime; 27248c2ecf20Sopenharmony_ci di->d_ino_timer = dm->dqb_itime; 27258c2ecf20Sopenharmony_ci spin_unlock(&dquot->dq_dqb_lock); 27268c2ecf20Sopenharmony_ci} 27278c2ecf20Sopenharmony_ci 27288c2ecf20Sopenharmony_ciint dquot_get_dqblk(struct super_block *sb, struct kqid qid, 27298c2ecf20Sopenharmony_ci struct qc_dqblk *di) 27308c2ecf20Sopenharmony_ci{ 27318c2ecf20Sopenharmony_ci struct dquot *dquot; 27328c2ecf20Sopenharmony_ci 27338c2ecf20Sopenharmony_ci dquot = dqget(sb, qid); 27348c2ecf20Sopenharmony_ci if (IS_ERR(dquot)) 27358c2ecf20Sopenharmony_ci return PTR_ERR(dquot); 27368c2ecf20Sopenharmony_ci do_get_dqblk(dquot, di); 27378c2ecf20Sopenharmony_ci dqput(dquot); 27388c2ecf20Sopenharmony_ci 27398c2ecf20Sopenharmony_ci return 0; 27408c2ecf20Sopenharmony_ci} 27418c2ecf20Sopenharmony_ciEXPORT_SYMBOL(dquot_get_dqblk); 27428c2ecf20Sopenharmony_ci 27438c2ecf20Sopenharmony_ciint dquot_get_next_dqblk(struct super_block *sb, struct kqid *qid, 27448c2ecf20Sopenharmony_ci struct qc_dqblk *di) 27458c2ecf20Sopenharmony_ci{ 27468c2ecf20Sopenharmony_ci struct dquot *dquot; 27478c2ecf20Sopenharmony_ci int err; 27488c2ecf20Sopenharmony_ci 27498c2ecf20Sopenharmony_ci if (!sb->dq_op->get_next_id) 27508c2ecf20Sopenharmony_ci return -ENOSYS; 27518c2ecf20Sopenharmony_ci err = sb->dq_op->get_next_id(sb, qid); 27528c2ecf20Sopenharmony_ci if (err < 0) 27538c2ecf20Sopenharmony_ci return err; 27548c2ecf20Sopenharmony_ci dquot = dqget(sb, *qid); 27558c2ecf20Sopenharmony_ci if (IS_ERR(dquot)) 27568c2ecf20Sopenharmony_ci return PTR_ERR(dquot); 27578c2ecf20Sopenharmony_ci do_get_dqblk(dquot, di); 27588c2ecf20Sopenharmony_ci dqput(dquot); 27598c2ecf20Sopenharmony_ci 27608c2ecf20Sopenharmony_ci return 0; 27618c2ecf20Sopenharmony_ci} 27628c2ecf20Sopenharmony_ciEXPORT_SYMBOL(dquot_get_next_dqblk); 27638c2ecf20Sopenharmony_ci 27648c2ecf20Sopenharmony_ci#define VFS_QC_MASK \ 27658c2ecf20Sopenharmony_ci (QC_SPACE | QC_SPC_SOFT | QC_SPC_HARD | \ 27668c2ecf20Sopenharmony_ci QC_INO_COUNT | QC_INO_SOFT | QC_INO_HARD | \ 27678c2ecf20Sopenharmony_ci QC_SPC_TIMER | QC_INO_TIMER) 27688c2ecf20Sopenharmony_ci 27698c2ecf20Sopenharmony_ci/* Generic routine for setting common part of quota structure */ 27708c2ecf20Sopenharmony_cistatic int do_set_dqblk(struct dquot *dquot, struct qc_dqblk *di) 27718c2ecf20Sopenharmony_ci{ 27728c2ecf20Sopenharmony_ci struct mem_dqblk *dm = &dquot->dq_dqb; 27738c2ecf20Sopenharmony_ci int check_blim = 0, check_ilim = 0; 27748c2ecf20Sopenharmony_ci struct mem_dqinfo *dqi = &sb_dqopt(dquot->dq_sb)->info[dquot->dq_id.type]; 27758c2ecf20Sopenharmony_ci 27768c2ecf20Sopenharmony_ci if (di->d_fieldmask & ~VFS_QC_MASK) 27778c2ecf20Sopenharmony_ci return -EINVAL; 27788c2ecf20Sopenharmony_ci 27798c2ecf20Sopenharmony_ci if (((di->d_fieldmask & QC_SPC_SOFT) && 27808c2ecf20Sopenharmony_ci di->d_spc_softlimit > dqi->dqi_max_spc_limit) || 27818c2ecf20Sopenharmony_ci ((di->d_fieldmask & QC_SPC_HARD) && 27828c2ecf20Sopenharmony_ci di->d_spc_hardlimit > dqi->dqi_max_spc_limit) || 27838c2ecf20Sopenharmony_ci ((di->d_fieldmask & QC_INO_SOFT) && 27848c2ecf20Sopenharmony_ci (di->d_ino_softlimit > dqi->dqi_max_ino_limit)) || 27858c2ecf20Sopenharmony_ci ((di->d_fieldmask & QC_INO_HARD) && 27868c2ecf20Sopenharmony_ci (di->d_ino_hardlimit > dqi->dqi_max_ino_limit))) 27878c2ecf20Sopenharmony_ci return -ERANGE; 27888c2ecf20Sopenharmony_ci 27898c2ecf20Sopenharmony_ci spin_lock(&dquot->dq_dqb_lock); 27908c2ecf20Sopenharmony_ci if (di->d_fieldmask & QC_SPACE) { 27918c2ecf20Sopenharmony_ci dm->dqb_curspace = di->d_space - dm->dqb_rsvspace; 27928c2ecf20Sopenharmony_ci check_blim = 1; 27938c2ecf20Sopenharmony_ci set_bit(DQ_LASTSET_B + QIF_SPACE_B, &dquot->dq_flags); 27948c2ecf20Sopenharmony_ci } 27958c2ecf20Sopenharmony_ci 27968c2ecf20Sopenharmony_ci if (di->d_fieldmask & QC_SPC_SOFT) 27978c2ecf20Sopenharmony_ci dm->dqb_bsoftlimit = di->d_spc_softlimit; 27988c2ecf20Sopenharmony_ci if (di->d_fieldmask & QC_SPC_HARD) 27998c2ecf20Sopenharmony_ci dm->dqb_bhardlimit = di->d_spc_hardlimit; 28008c2ecf20Sopenharmony_ci if (di->d_fieldmask & (QC_SPC_SOFT | QC_SPC_HARD)) { 28018c2ecf20Sopenharmony_ci check_blim = 1; 28028c2ecf20Sopenharmony_ci set_bit(DQ_LASTSET_B + QIF_BLIMITS_B, &dquot->dq_flags); 28038c2ecf20Sopenharmony_ci } 28048c2ecf20Sopenharmony_ci 28058c2ecf20Sopenharmony_ci if (di->d_fieldmask & QC_INO_COUNT) { 28068c2ecf20Sopenharmony_ci dm->dqb_curinodes = di->d_ino_count; 28078c2ecf20Sopenharmony_ci check_ilim = 1; 28088c2ecf20Sopenharmony_ci set_bit(DQ_LASTSET_B + QIF_INODES_B, &dquot->dq_flags); 28098c2ecf20Sopenharmony_ci } 28108c2ecf20Sopenharmony_ci 28118c2ecf20Sopenharmony_ci if (di->d_fieldmask & QC_INO_SOFT) 28128c2ecf20Sopenharmony_ci dm->dqb_isoftlimit = di->d_ino_softlimit; 28138c2ecf20Sopenharmony_ci if (di->d_fieldmask & QC_INO_HARD) 28148c2ecf20Sopenharmony_ci dm->dqb_ihardlimit = di->d_ino_hardlimit; 28158c2ecf20Sopenharmony_ci if (di->d_fieldmask & (QC_INO_SOFT | QC_INO_HARD)) { 28168c2ecf20Sopenharmony_ci check_ilim = 1; 28178c2ecf20Sopenharmony_ci set_bit(DQ_LASTSET_B + QIF_ILIMITS_B, &dquot->dq_flags); 28188c2ecf20Sopenharmony_ci } 28198c2ecf20Sopenharmony_ci 28208c2ecf20Sopenharmony_ci if (di->d_fieldmask & QC_SPC_TIMER) { 28218c2ecf20Sopenharmony_ci dm->dqb_btime = di->d_spc_timer; 28228c2ecf20Sopenharmony_ci check_blim = 1; 28238c2ecf20Sopenharmony_ci set_bit(DQ_LASTSET_B + QIF_BTIME_B, &dquot->dq_flags); 28248c2ecf20Sopenharmony_ci } 28258c2ecf20Sopenharmony_ci 28268c2ecf20Sopenharmony_ci if (di->d_fieldmask & QC_INO_TIMER) { 28278c2ecf20Sopenharmony_ci dm->dqb_itime = di->d_ino_timer; 28288c2ecf20Sopenharmony_ci check_ilim = 1; 28298c2ecf20Sopenharmony_ci set_bit(DQ_LASTSET_B + QIF_ITIME_B, &dquot->dq_flags); 28308c2ecf20Sopenharmony_ci } 28318c2ecf20Sopenharmony_ci 28328c2ecf20Sopenharmony_ci if (check_blim) { 28338c2ecf20Sopenharmony_ci if (!dm->dqb_bsoftlimit || 28348c2ecf20Sopenharmony_ci dm->dqb_curspace + dm->dqb_rsvspace <= dm->dqb_bsoftlimit) { 28358c2ecf20Sopenharmony_ci dm->dqb_btime = 0; 28368c2ecf20Sopenharmony_ci clear_bit(DQ_BLKS_B, &dquot->dq_flags); 28378c2ecf20Sopenharmony_ci } else if (!(di->d_fieldmask & QC_SPC_TIMER)) 28388c2ecf20Sopenharmony_ci /* Set grace only if user hasn't provided his own... */ 28398c2ecf20Sopenharmony_ci dm->dqb_btime = ktime_get_real_seconds() + dqi->dqi_bgrace; 28408c2ecf20Sopenharmony_ci } 28418c2ecf20Sopenharmony_ci if (check_ilim) { 28428c2ecf20Sopenharmony_ci if (!dm->dqb_isoftlimit || 28438c2ecf20Sopenharmony_ci dm->dqb_curinodes <= dm->dqb_isoftlimit) { 28448c2ecf20Sopenharmony_ci dm->dqb_itime = 0; 28458c2ecf20Sopenharmony_ci clear_bit(DQ_INODES_B, &dquot->dq_flags); 28468c2ecf20Sopenharmony_ci } else if (!(di->d_fieldmask & QC_INO_TIMER)) 28478c2ecf20Sopenharmony_ci /* Set grace only if user hasn't provided his own... */ 28488c2ecf20Sopenharmony_ci dm->dqb_itime = ktime_get_real_seconds() + dqi->dqi_igrace; 28498c2ecf20Sopenharmony_ci } 28508c2ecf20Sopenharmony_ci if (dm->dqb_bhardlimit || dm->dqb_bsoftlimit || dm->dqb_ihardlimit || 28518c2ecf20Sopenharmony_ci dm->dqb_isoftlimit) 28528c2ecf20Sopenharmony_ci clear_bit(DQ_FAKE_B, &dquot->dq_flags); 28538c2ecf20Sopenharmony_ci else 28548c2ecf20Sopenharmony_ci set_bit(DQ_FAKE_B, &dquot->dq_flags); 28558c2ecf20Sopenharmony_ci spin_unlock(&dquot->dq_dqb_lock); 28568c2ecf20Sopenharmony_ci mark_dquot_dirty(dquot); 28578c2ecf20Sopenharmony_ci 28588c2ecf20Sopenharmony_ci return 0; 28598c2ecf20Sopenharmony_ci} 28608c2ecf20Sopenharmony_ci 28618c2ecf20Sopenharmony_ciint dquot_set_dqblk(struct super_block *sb, struct kqid qid, 28628c2ecf20Sopenharmony_ci struct qc_dqblk *di) 28638c2ecf20Sopenharmony_ci{ 28648c2ecf20Sopenharmony_ci struct dquot *dquot; 28658c2ecf20Sopenharmony_ci int rc; 28668c2ecf20Sopenharmony_ci 28678c2ecf20Sopenharmony_ci dquot = dqget(sb, qid); 28688c2ecf20Sopenharmony_ci if (IS_ERR(dquot)) { 28698c2ecf20Sopenharmony_ci rc = PTR_ERR(dquot); 28708c2ecf20Sopenharmony_ci goto out; 28718c2ecf20Sopenharmony_ci } 28728c2ecf20Sopenharmony_ci rc = do_set_dqblk(dquot, di); 28738c2ecf20Sopenharmony_ci dqput(dquot); 28748c2ecf20Sopenharmony_ciout: 28758c2ecf20Sopenharmony_ci return rc; 28768c2ecf20Sopenharmony_ci} 28778c2ecf20Sopenharmony_ciEXPORT_SYMBOL(dquot_set_dqblk); 28788c2ecf20Sopenharmony_ci 28798c2ecf20Sopenharmony_ci/* Generic routine for getting common part of quota file information */ 28808c2ecf20Sopenharmony_ciint dquot_get_state(struct super_block *sb, struct qc_state *state) 28818c2ecf20Sopenharmony_ci{ 28828c2ecf20Sopenharmony_ci struct mem_dqinfo *mi; 28838c2ecf20Sopenharmony_ci struct qc_type_state *tstate; 28848c2ecf20Sopenharmony_ci struct quota_info *dqopt = sb_dqopt(sb); 28858c2ecf20Sopenharmony_ci int type; 28868c2ecf20Sopenharmony_ci 28878c2ecf20Sopenharmony_ci memset(state, 0, sizeof(*state)); 28888c2ecf20Sopenharmony_ci for (type = 0; type < MAXQUOTAS; type++) { 28898c2ecf20Sopenharmony_ci if (!sb_has_quota_active(sb, type)) 28908c2ecf20Sopenharmony_ci continue; 28918c2ecf20Sopenharmony_ci tstate = state->s_state + type; 28928c2ecf20Sopenharmony_ci mi = sb_dqopt(sb)->info + type; 28938c2ecf20Sopenharmony_ci tstate->flags = QCI_ACCT_ENABLED; 28948c2ecf20Sopenharmony_ci spin_lock(&dq_data_lock); 28958c2ecf20Sopenharmony_ci if (mi->dqi_flags & DQF_SYS_FILE) 28968c2ecf20Sopenharmony_ci tstate->flags |= QCI_SYSFILE; 28978c2ecf20Sopenharmony_ci if (mi->dqi_flags & DQF_ROOT_SQUASH) 28988c2ecf20Sopenharmony_ci tstate->flags |= QCI_ROOT_SQUASH; 28998c2ecf20Sopenharmony_ci if (sb_has_quota_limits_enabled(sb, type)) 29008c2ecf20Sopenharmony_ci tstate->flags |= QCI_LIMITS_ENFORCED; 29018c2ecf20Sopenharmony_ci tstate->spc_timelimit = mi->dqi_bgrace; 29028c2ecf20Sopenharmony_ci tstate->ino_timelimit = mi->dqi_igrace; 29038c2ecf20Sopenharmony_ci if (dqopt->files[type]) { 29048c2ecf20Sopenharmony_ci tstate->ino = dqopt->files[type]->i_ino; 29058c2ecf20Sopenharmony_ci tstate->blocks = dqopt->files[type]->i_blocks; 29068c2ecf20Sopenharmony_ci } 29078c2ecf20Sopenharmony_ci tstate->nextents = 1; /* We don't know... */ 29088c2ecf20Sopenharmony_ci spin_unlock(&dq_data_lock); 29098c2ecf20Sopenharmony_ci } 29108c2ecf20Sopenharmony_ci return 0; 29118c2ecf20Sopenharmony_ci} 29128c2ecf20Sopenharmony_ciEXPORT_SYMBOL(dquot_get_state); 29138c2ecf20Sopenharmony_ci 29148c2ecf20Sopenharmony_ci/* Generic routine for setting common part of quota file information */ 29158c2ecf20Sopenharmony_ciint dquot_set_dqinfo(struct super_block *sb, int type, struct qc_info *ii) 29168c2ecf20Sopenharmony_ci{ 29178c2ecf20Sopenharmony_ci struct mem_dqinfo *mi; 29188c2ecf20Sopenharmony_ci int err = 0; 29198c2ecf20Sopenharmony_ci 29208c2ecf20Sopenharmony_ci if ((ii->i_fieldmask & QC_WARNS_MASK) || 29218c2ecf20Sopenharmony_ci (ii->i_fieldmask & QC_RT_SPC_TIMER)) 29228c2ecf20Sopenharmony_ci return -EINVAL; 29238c2ecf20Sopenharmony_ci if (!sb_has_quota_active(sb, type)) 29248c2ecf20Sopenharmony_ci return -ESRCH; 29258c2ecf20Sopenharmony_ci mi = sb_dqopt(sb)->info + type; 29268c2ecf20Sopenharmony_ci if (ii->i_fieldmask & QC_FLAGS) { 29278c2ecf20Sopenharmony_ci if ((ii->i_flags & QCI_ROOT_SQUASH && 29288c2ecf20Sopenharmony_ci mi->dqi_format->qf_fmt_id != QFMT_VFS_OLD)) 29298c2ecf20Sopenharmony_ci return -EINVAL; 29308c2ecf20Sopenharmony_ci } 29318c2ecf20Sopenharmony_ci spin_lock(&dq_data_lock); 29328c2ecf20Sopenharmony_ci if (ii->i_fieldmask & QC_SPC_TIMER) 29338c2ecf20Sopenharmony_ci mi->dqi_bgrace = ii->i_spc_timelimit; 29348c2ecf20Sopenharmony_ci if (ii->i_fieldmask & QC_INO_TIMER) 29358c2ecf20Sopenharmony_ci mi->dqi_igrace = ii->i_ino_timelimit; 29368c2ecf20Sopenharmony_ci if (ii->i_fieldmask & QC_FLAGS) { 29378c2ecf20Sopenharmony_ci if (ii->i_flags & QCI_ROOT_SQUASH) 29388c2ecf20Sopenharmony_ci mi->dqi_flags |= DQF_ROOT_SQUASH; 29398c2ecf20Sopenharmony_ci else 29408c2ecf20Sopenharmony_ci mi->dqi_flags &= ~DQF_ROOT_SQUASH; 29418c2ecf20Sopenharmony_ci } 29428c2ecf20Sopenharmony_ci spin_unlock(&dq_data_lock); 29438c2ecf20Sopenharmony_ci mark_info_dirty(sb, type); 29448c2ecf20Sopenharmony_ci /* Force write to disk */ 29458c2ecf20Sopenharmony_ci sb->dq_op->write_info(sb, type); 29468c2ecf20Sopenharmony_ci return err; 29478c2ecf20Sopenharmony_ci} 29488c2ecf20Sopenharmony_ciEXPORT_SYMBOL(dquot_set_dqinfo); 29498c2ecf20Sopenharmony_ci 29508c2ecf20Sopenharmony_ciconst struct quotactl_ops dquot_quotactl_sysfile_ops = { 29518c2ecf20Sopenharmony_ci .quota_enable = dquot_quota_enable, 29528c2ecf20Sopenharmony_ci .quota_disable = dquot_quota_disable, 29538c2ecf20Sopenharmony_ci .quota_sync = dquot_quota_sync, 29548c2ecf20Sopenharmony_ci .get_state = dquot_get_state, 29558c2ecf20Sopenharmony_ci .set_info = dquot_set_dqinfo, 29568c2ecf20Sopenharmony_ci .get_dqblk = dquot_get_dqblk, 29578c2ecf20Sopenharmony_ci .get_nextdqblk = dquot_get_next_dqblk, 29588c2ecf20Sopenharmony_ci .set_dqblk = dquot_set_dqblk 29598c2ecf20Sopenharmony_ci}; 29608c2ecf20Sopenharmony_ciEXPORT_SYMBOL(dquot_quotactl_sysfile_ops); 29618c2ecf20Sopenharmony_ci 29628c2ecf20Sopenharmony_cistatic int do_proc_dqstats(struct ctl_table *table, int write, 29638c2ecf20Sopenharmony_ci void *buffer, size_t *lenp, loff_t *ppos) 29648c2ecf20Sopenharmony_ci{ 29658c2ecf20Sopenharmony_ci unsigned int type = (unsigned long *)table->data - dqstats.stat; 29668c2ecf20Sopenharmony_ci s64 value = percpu_counter_sum(&dqstats.counter[type]); 29678c2ecf20Sopenharmony_ci 29688c2ecf20Sopenharmony_ci /* Filter negative values for non-monotonic counters */ 29698c2ecf20Sopenharmony_ci if (value < 0 && (type == DQST_ALLOC_DQUOTS || 29708c2ecf20Sopenharmony_ci type == DQST_FREE_DQUOTS)) 29718c2ecf20Sopenharmony_ci value = 0; 29728c2ecf20Sopenharmony_ci 29738c2ecf20Sopenharmony_ci /* Update global table */ 29748c2ecf20Sopenharmony_ci dqstats.stat[type] = value; 29758c2ecf20Sopenharmony_ci return proc_doulongvec_minmax(table, write, buffer, lenp, ppos); 29768c2ecf20Sopenharmony_ci} 29778c2ecf20Sopenharmony_ci 29788c2ecf20Sopenharmony_cistatic struct ctl_table fs_dqstats_table[] = { 29798c2ecf20Sopenharmony_ci { 29808c2ecf20Sopenharmony_ci .procname = "lookups", 29818c2ecf20Sopenharmony_ci .data = &dqstats.stat[DQST_LOOKUPS], 29828c2ecf20Sopenharmony_ci .maxlen = sizeof(unsigned long), 29838c2ecf20Sopenharmony_ci .mode = 0444, 29848c2ecf20Sopenharmony_ci .proc_handler = do_proc_dqstats, 29858c2ecf20Sopenharmony_ci }, 29868c2ecf20Sopenharmony_ci { 29878c2ecf20Sopenharmony_ci .procname = "drops", 29888c2ecf20Sopenharmony_ci .data = &dqstats.stat[DQST_DROPS], 29898c2ecf20Sopenharmony_ci .maxlen = sizeof(unsigned long), 29908c2ecf20Sopenharmony_ci .mode = 0444, 29918c2ecf20Sopenharmony_ci .proc_handler = do_proc_dqstats, 29928c2ecf20Sopenharmony_ci }, 29938c2ecf20Sopenharmony_ci { 29948c2ecf20Sopenharmony_ci .procname = "reads", 29958c2ecf20Sopenharmony_ci .data = &dqstats.stat[DQST_READS], 29968c2ecf20Sopenharmony_ci .maxlen = sizeof(unsigned long), 29978c2ecf20Sopenharmony_ci .mode = 0444, 29988c2ecf20Sopenharmony_ci .proc_handler = do_proc_dqstats, 29998c2ecf20Sopenharmony_ci }, 30008c2ecf20Sopenharmony_ci { 30018c2ecf20Sopenharmony_ci .procname = "writes", 30028c2ecf20Sopenharmony_ci .data = &dqstats.stat[DQST_WRITES], 30038c2ecf20Sopenharmony_ci .maxlen = sizeof(unsigned long), 30048c2ecf20Sopenharmony_ci .mode = 0444, 30058c2ecf20Sopenharmony_ci .proc_handler = do_proc_dqstats, 30068c2ecf20Sopenharmony_ci }, 30078c2ecf20Sopenharmony_ci { 30088c2ecf20Sopenharmony_ci .procname = "cache_hits", 30098c2ecf20Sopenharmony_ci .data = &dqstats.stat[DQST_CACHE_HITS], 30108c2ecf20Sopenharmony_ci .maxlen = sizeof(unsigned long), 30118c2ecf20Sopenharmony_ci .mode = 0444, 30128c2ecf20Sopenharmony_ci .proc_handler = do_proc_dqstats, 30138c2ecf20Sopenharmony_ci }, 30148c2ecf20Sopenharmony_ci { 30158c2ecf20Sopenharmony_ci .procname = "allocated_dquots", 30168c2ecf20Sopenharmony_ci .data = &dqstats.stat[DQST_ALLOC_DQUOTS], 30178c2ecf20Sopenharmony_ci .maxlen = sizeof(unsigned long), 30188c2ecf20Sopenharmony_ci .mode = 0444, 30198c2ecf20Sopenharmony_ci .proc_handler = do_proc_dqstats, 30208c2ecf20Sopenharmony_ci }, 30218c2ecf20Sopenharmony_ci { 30228c2ecf20Sopenharmony_ci .procname = "free_dquots", 30238c2ecf20Sopenharmony_ci .data = &dqstats.stat[DQST_FREE_DQUOTS], 30248c2ecf20Sopenharmony_ci .maxlen = sizeof(unsigned long), 30258c2ecf20Sopenharmony_ci .mode = 0444, 30268c2ecf20Sopenharmony_ci .proc_handler = do_proc_dqstats, 30278c2ecf20Sopenharmony_ci }, 30288c2ecf20Sopenharmony_ci { 30298c2ecf20Sopenharmony_ci .procname = "syncs", 30308c2ecf20Sopenharmony_ci .data = &dqstats.stat[DQST_SYNCS], 30318c2ecf20Sopenharmony_ci .maxlen = sizeof(unsigned long), 30328c2ecf20Sopenharmony_ci .mode = 0444, 30338c2ecf20Sopenharmony_ci .proc_handler = do_proc_dqstats, 30348c2ecf20Sopenharmony_ci }, 30358c2ecf20Sopenharmony_ci#ifdef CONFIG_PRINT_QUOTA_WARNING 30368c2ecf20Sopenharmony_ci { 30378c2ecf20Sopenharmony_ci .procname = "warnings", 30388c2ecf20Sopenharmony_ci .data = &flag_print_warnings, 30398c2ecf20Sopenharmony_ci .maxlen = sizeof(int), 30408c2ecf20Sopenharmony_ci .mode = 0644, 30418c2ecf20Sopenharmony_ci .proc_handler = proc_dointvec, 30428c2ecf20Sopenharmony_ci }, 30438c2ecf20Sopenharmony_ci#endif 30448c2ecf20Sopenharmony_ci { }, 30458c2ecf20Sopenharmony_ci}; 30468c2ecf20Sopenharmony_ci 30478c2ecf20Sopenharmony_cistatic struct ctl_table fs_table[] = { 30488c2ecf20Sopenharmony_ci { 30498c2ecf20Sopenharmony_ci .procname = "quota", 30508c2ecf20Sopenharmony_ci .mode = 0555, 30518c2ecf20Sopenharmony_ci .child = fs_dqstats_table, 30528c2ecf20Sopenharmony_ci }, 30538c2ecf20Sopenharmony_ci { }, 30548c2ecf20Sopenharmony_ci}; 30558c2ecf20Sopenharmony_ci 30568c2ecf20Sopenharmony_cistatic struct ctl_table sys_table[] = { 30578c2ecf20Sopenharmony_ci { 30588c2ecf20Sopenharmony_ci .procname = "fs", 30598c2ecf20Sopenharmony_ci .mode = 0555, 30608c2ecf20Sopenharmony_ci .child = fs_table, 30618c2ecf20Sopenharmony_ci }, 30628c2ecf20Sopenharmony_ci { }, 30638c2ecf20Sopenharmony_ci}; 30648c2ecf20Sopenharmony_ci 30658c2ecf20Sopenharmony_cistatic int __init dquot_init(void) 30668c2ecf20Sopenharmony_ci{ 30678c2ecf20Sopenharmony_ci int i, ret; 30688c2ecf20Sopenharmony_ci unsigned long nr_hash, order; 30698c2ecf20Sopenharmony_ci 30708c2ecf20Sopenharmony_ci printk(KERN_NOTICE "VFS: Disk quotas %s\n", __DQUOT_VERSION__); 30718c2ecf20Sopenharmony_ci 30728c2ecf20Sopenharmony_ci register_sysctl_table(sys_table); 30738c2ecf20Sopenharmony_ci 30748c2ecf20Sopenharmony_ci dquot_cachep = kmem_cache_create("dquot", 30758c2ecf20Sopenharmony_ci sizeof(struct dquot), sizeof(unsigned long) * 4, 30768c2ecf20Sopenharmony_ci (SLAB_HWCACHE_ALIGN|SLAB_RECLAIM_ACCOUNT| 30778c2ecf20Sopenharmony_ci SLAB_MEM_SPREAD|SLAB_PANIC), 30788c2ecf20Sopenharmony_ci NULL); 30798c2ecf20Sopenharmony_ci 30808c2ecf20Sopenharmony_ci order = 0; 30818c2ecf20Sopenharmony_ci dquot_hash = (struct hlist_head *)__get_free_pages(GFP_KERNEL, order); 30828c2ecf20Sopenharmony_ci if (!dquot_hash) 30838c2ecf20Sopenharmony_ci panic("Cannot create dquot hash table"); 30848c2ecf20Sopenharmony_ci 30858c2ecf20Sopenharmony_ci for (i = 0; i < _DQST_DQSTAT_LAST; i++) { 30868c2ecf20Sopenharmony_ci ret = percpu_counter_init(&dqstats.counter[i], 0, GFP_KERNEL); 30878c2ecf20Sopenharmony_ci if (ret) 30888c2ecf20Sopenharmony_ci panic("Cannot create dquot stat counters"); 30898c2ecf20Sopenharmony_ci } 30908c2ecf20Sopenharmony_ci 30918c2ecf20Sopenharmony_ci /* Find power-of-two hlist_heads which can fit into allocation */ 30928c2ecf20Sopenharmony_ci nr_hash = (1UL << order) * PAGE_SIZE / sizeof(struct hlist_head); 30938c2ecf20Sopenharmony_ci dq_hash_bits = ilog2(nr_hash); 30948c2ecf20Sopenharmony_ci 30958c2ecf20Sopenharmony_ci nr_hash = 1UL << dq_hash_bits; 30968c2ecf20Sopenharmony_ci dq_hash_mask = nr_hash - 1; 30978c2ecf20Sopenharmony_ci for (i = 0; i < nr_hash; i++) 30988c2ecf20Sopenharmony_ci INIT_HLIST_HEAD(dquot_hash + i); 30998c2ecf20Sopenharmony_ci 31008c2ecf20Sopenharmony_ci pr_info("VFS: Dquot-cache hash table entries: %ld (order %ld," 31018c2ecf20Sopenharmony_ci " %ld bytes)\n", nr_hash, order, (PAGE_SIZE << order)); 31028c2ecf20Sopenharmony_ci 31038c2ecf20Sopenharmony_ci if (register_shrinker(&dqcache_shrinker)) 31048c2ecf20Sopenharmony_ci panic("Cannot register dquot shrinker"); 31058c2ecf20Sopenharmony_ci 31068c2ecf20Sopenharmony_ci return 0; 31078c2ecf20Sopenharmony_ci} 31088c2ecf20Sopenharmony_cifs_initcall(dquot_init); 3109