xref: /linux/mm/shmem_quota.c (revision dc189b8e6adbe113a6d4b3a7c5d0c9cd7febb3bb)
1eafc474eSCarlos Maiolino // SPDX-License-Identifier: GPL-2.0-only
2eafc474eSCarlos Maiolino /*
3eafc474eSCarlos Maiolino  * In memory quota format relies on quota infrastructure to store dquot
4eafc474eSCarlos Maiolino  * information for us. While conventional quota formats for file systems
5eafc474eSCarlos Maiolino  * with persistent storage can load quota information into dquot from the
6eafc474eSCarlos Maiolino  * storage on-demand and hence quota dquot shrinker can free any dquot
7eafc474eSCarlos Maiolino  * that is not currently being used, it must be avoided here. Otherwise we
8eafc474eSCarlos Maiolino  * can lose valuable information, user provided limits, because there is
9eafc474eSCarlos Maiolino  * no persistent storage to load the information from afterwards.
10eafc474eSCarlos Maiolino  *
11eafc474eSCarlos Maiolino  * One information that in-memory quota format needs to keep track of is
12eafc474eSCarlos Maiolino  * a sorted list of ids for each quota type. This is done by utilizing
13eafc474eSCarlos Maiolino  * an rb tree which root is stored in mem_dqinfo->dqi_priv for each quota
14eafc474eSCarlos Maiolino  * type.
15eafc474eSCarlos Maiolino  *
16eafc474eSCarlos Maiolino  * This format can be used to support quota on file system without persistent
17eafc474eSCarlos Maiolino  * storage such as tmpfs.
18eafc474eSCarlos Maiolino  *
19eafc474eSCarlos Maiolino  * Author:	Lukas Czerner <lczerner@redhat.com>
20eafc474eSCarlos Maiolino  *		Carlos Maiolino <cmaiolino@redhat.com>
21eafc474eSCarlos Maiolino  *
22eafc474eSCarlos Maiolino  * Copyright (C) 2023 Red Hat, Inc.
23eafc474eSCarlos Maiolino  */
24eafc474eSCarlos Maiolino #include <linux/errno.h>
25eafc474eSCarlos Maiolino #include <linux/fs.h>
26eafc474eSCarlos Maiolino #include <linux/mount.h>
27eafc474eSCarlos Maiolino #include <linux/kernel.h>
28eafc474eSCarlos Maiolino #include <linux/init.h>
29eafc474eSCarlos Maiolino #include <linux/module.h>
30eafc474eSCarlos Maiolino #include <linux/slab.h>
31eafc474eSCarlos Maiolino #include <linux/rbtree.h>
32eafc474eSCarlos Maiolino #include <linux/shmem_fs.h>
33eafc474eSCarlos Maiolino 
34eafc474eSCarlos Maiolino #include <linux/quotaops.h>
35eafc474eSCarlos Maiolino #include <linux/quota.h>
36eafc474eSCarlos Maiolino 
37eafc474eSCarlos Maiolino #ifdef CONFIG_TMPFS_QUOTA
38eafc474eSCarlos Maiolino 
39eafc474eSCarlos Maiolino /*
40eafc474eSCarlos Maiolino  * The following constants define the amount of time given a user
41eafc474eSCarlos Maiolino  * before the soft limits are treated as hard limits (usually resulting
42eafc474eSCarlos Maiolino  * in an allocation failure). The timer is started when the user crosses
43eafc474eSCarlos Maiolino  * their soft limit, it is reset when they go below their soft limit.
44eafc474eSCarlos Maiolino  */
45eafc474eSCarlos Maiolino #define SHMEM_MAX_IQ_TIME 604800	/* (7*24*60*60) 1 week */
46eafc474eSCarlos Maiolino #define SHMEM_MAX_DQ_TIME 604800	/* (7*24*60*60) 1 week */
47eafc474eSCarlos Maiolino 
48eafc474eSCarlos Maiolino struct quota_id {
49eafc474eSCarlos Maiolino 	struct rb_node	node;
50eafc474eSCarlos Maiolino 	qid_t		id;
51eafc474eSCarlos Maiolino 	qsize_t		bhardlimit;
52eafc474eSCarlos Maiolino 	qsize_t		bsoftlimit;
53eafc474eSCarlos Maiolino 	qsize_t		ihardlimit;
54eafc474eSCarlos Maiolino 	qsize_t		isoftlimit;
55eafc474eSCarlos Maiolino };
56eafc474eSCarlos Maiolino 
shmem_check_quota_file(struct super_block * sb,int type)57eafc474eSCarlos Maiolino static int shmem_check_quota_file(struct super_block *sb, int type)
58eafc474eSCarlos Maiolino {
59eafc474eSCarlos Maiolino 	/* There is no real quota file, nothing to do */
60eafc474eSCarlos Maiolino 	return 1;
61eafc474eSCarlos Maiolino }
62eafc474eSCarlos Maiolino 
63eafc474eSCarlos Maiolino /*
64eafc474eSCarlos Maiolino  * There is no real quota file. Just allocate rb_root for quota ids and
65eafc474eSCarlos Maiolino  * set limits
66eafc474eSCarlos Maiolino  */
shmem_read_file_info(struct super_block * sb,int type)67eafc474eSCarlos Maiolino static int shmem_read_file_info(struct super_block *sb, int type)
68eafc474eSCarlos Maiolino {
69eafc474eSCarlos Maiolino 	struct quota_info *dqopt = sb_dqopt(sb);
70eafc474eSCarlos Maiolino 	struct mem_dqinfo *info = &dqopt->info[type];
71eafc474eSCarlos Maiolino 
72eafc474eSCarlos Maiolino 	info->dqi_priv = kzalloc(sizeof(struct rb_root), GFP_NOFS);
73eafc474eSCarlos Maiolino 	if (!info->dqi_priv)
74eafc474eSCarlos Maiolino 		return -ENOMEM;
75eafc474eSCarlos Maiolino 
76eafc474eSCarlos Maiolino 	info->dqi_max_spc_limit = SHMEM_QUOTA_MAX_SPC_LIMIT;
77eafc474eSCarlos Maiolino 	info->dqi_max_ino_limit = SHMEM_QUOTA_MAX_INO_LIMIT;
78eafc474eSCarlos Maiolino 
79eafc474eSCarlos Maiolino 	info->dqi_bgrace = SHMEM_MAX_DQ_TIME;
80eafc474eSCarlos Maiolino 	info->dqi_igrace = SHMEM_MAX_IQ_TIME;
81eafc474eSCarlos Maiolino 	info->dqi_flags = 0;
82eafc474eSCarlos Maiolino 
83eafc474eSCarlos Maiolino 	return 0;
84eafc474eSCarlos Maiolino }
85eafc474eSCarlos Maiolino 
shmem_write_file_info(struct super_block * sb,int type)86eafc474eSCarlos Maiolino static int shmem_write_file_info(struct super_block *sb, int type)
87eafc474eSCarlos Maiolino {
88eafc474eSCarlos Maiolino 	/* There is no real quota file, nothing to do */
89eafc474eSCarlos Maiolino 	return 0;
90eafc474eSCarlos Maiolino }
91eafc474eSCarlos Maiolino 
92eafc474eSCarlos Maiolino /*
93eafc474eSCarlos Maiolino  * Free all the quota_id entries in the rb tree and rb_root.
94eafc474eSCarlos Maiolino  */
shmem_free_file_info(struct super_block * sb,int type)95eafc474eSCarlos Maiolino static int shmem_free_file_info(struct super_block *sb, int type)
96eafc474eSCarlos Maiolino {
97eafc474eSCarlos Maiolino 	struct mem_dqinfo *info = &sb_dqopt(sb)->info[type];
98eafc474eSCarlos Maiolino 	struct rb_root *root = info->dqi_priv;
99eafc474eSCarlos Maiolino 	struct quota_id *entry;
100eafc474eSCarlos Maiolino 	struct rb_node *node;
101eafc474eSCarlos Maiolino 
102eafc474eSCarlos Maiolino 	info->dqi_priv = NULL;
103eafc474eSCarlos Maiolino 	node = rb_first(root);
104eafc474eSCarlos Maiolino 	while (node) {
105eafc474eSCarlos Maiolino 		entry = rb_entry(node, struct quota_id, node);
106eafc474eSCarlos Maiolino 		node = rb_next(&entry->node);
107eafc474eSCarlos Maiolino 
108eafc474eSCarlos Maiolino 		rb_erase(&entry->node, root);
109eafc474eSCarlos Maiolino 		kfree(entry);
110eafc474eSCarlos Maiolino 	}
111eafc474eSCarlos Maiolino 
112eafc474eSCarlos Maiolino 	kfree(root);
113eafc474eSCarlos Maiolino 	return 0;
114eafc474eSCarlos Maiolino }
115eafc474eSCarlos Maiolino 
shmem_get_next_id(struct super_block * sb,struct kqid * qid)116eafc474eSCarlos Maiolino static int shmem_get_next_id(struct super_block *sb, struct kqid *qid)
117eafc474eSCarlos Maiolino {
118eafc474eSCarlos Maiolino 	struct mem_dqinfo *info = sb_dqinfo(sb, qid->type);
119*0a69b6b3SCarlos Maiolino 	struct rb_node *node;
120eafc474eSCarlos Maiolino 	qid_t id = from_kqid(&init_user_ns, *qid);
121eafc474eSCarlos Maiolino 	struct quota_info *dqopt = sb_dqopt(sb);
122eafc474eSCarlos Maiolino 	struct quota_id *entry = NULL;
123eafc474eSCarlos Maiolino 	int ret = 0;
124eafc474eSCarlos Maiolino 
125eafc474eSCarlos Maiolino 	if (!sb_has_quota_active(sb, qid->type))
126eafc474eSCarlos Maiolino 		return -ESRCH;
127eafc474eSCarlos Maiolino 
128eafc474eSCarlos Maiolino 	down_read(&dqopt->dqio_sem);
129*0a69b6b3SCarlos Maiolino 	node = ((struct rb_root *)info->dqi_priv)->rb_node;
130eafc474eSCarlos Maiolino 	while (node) {
131eafc474eSCarlos Maiolino 		entry = rb_entry(node, struct quota_id, node);
132eafc474eSCarlos Maiolino 
133eafc474eSCarlos Maiolino 		if (id < entry->id)
134eafc474eSCarlos Maiolino 			node = node->rb_left;
135eafc474eSCarlos Maiolino 		else if (id > entry->id)
136eafc474eSCarlos Maiolino 			node = node->rb_right;
137eafc474eSCarlos Maiolino 		else
138eafc474eSCarlos Maiolino 			goto got_next_id;
139eafc474eSCarlos Maiolino 	}
140eafc474eSCarlos Maiolino 
141eafc474eSCarlos Maiolino 	if (!entry) {
142eafc474eSCarlos Maiolino 		ret = -ENOENT;
143eafc474eSCarlos Maiolino 		goto out_unlock;
144eafc474eSCarlos Maiolino 	}
145eafc474eSCarlos Maiolino 
146eafc474eSCarlos Maiolino 	if (id > entry->id) {
147eafc474eSCarlos Maiolino 		node = rb_next(&entry->node);
148eafc474eSCarlos Maiolino 		if (!node) {
149eafc474eSCarlos Maiolino 			ret = -ENOENT;
150eafc474eSCarlos Maiolino 			goto out_unlock;
151eafc474eSCarlos Maiolino 		}
152eafc474eSCarlos Maiolino 		entry = rb_entry(node, struct quota_id, node);
153eafc474eSCarlos Maiolino 	}
154eafc474eSCarlos Maiolino 
155eafc474eSCarlos Maiolino got_next_id:
156eafc474eSCarlos Maiolino 	*qid = make_kqid(&init_user_ns, qid->type, entry->id);
157eafc474eSCarlos Maiolino out_unlock:
158eafc474eSCarlos Maiolino 	up_read(&dqopt->dqio_sem);
159eafc474eSCarlos Maiolino 	return ret;
160eafc474eSCarlos Maiolino }
161eafc474eSCarlos Maiolino 
162eafc474eSCarlos Maiolino /*
163eafc474eSCarlos Maiolino  * Load dquot with limits from existing entry, or create the new entry if
164eafc474eSCarlos Maiolino  * it does not exist.
165eafc474eSCarlos Maiolino  */
shmem_acquire_dquot(struct dquot * dquot)166eafc474eSCarlos Maiolino static int shmem_acquire_dquot(struct dquot *dquot)
167eafc474eSCarlos Maiolino {
168eafc474eSCarlos Maiolino 	struct mem_dqinfo *info = sb_dqinfo(dquot->dq_sb, dquot->dq_id.type);
169*0a69b6b3SCarlos Maiolino 	struct rb_node **n;
170de4c0e7cSLukas Czerner 	struct shmem_sb_info *sbinfo = dquot->dq_sb->s_fs_info;
171eafc474eSCarlos Maiolino 	struct rb_node *parent = NULL, *new_node = NULL;
172eafc474eSCarlos Maiolino 	struct quota_id *new_entry, *entry;
173eafc474eSCarlos Maiolino 	qid_t id = from_kqid(&init_user_ns, dquot->dq_id);
174eafc474eSCarlos Maiolino 	struct quota_info *dqopt = sb_dqopt(dquot->dq_sb);
175eafc474eSCarlos Maiolino 	int ret = 0;
176eafc474eSCarlos Maiolino 
177eafc474eSCarlos Maiolino 	mutex_lock(&dquot->dq_lock);
178eafc474eSCarlos Maiolino 
179eafc474eSCarlos Maiolino 	down_write(&dqopt->dqio_sem);
180*0a69b6b3SCarlos Maiolino 	n = &((struct rb_root *)info->dqi_priv)->rb_node;
181*0a69b6b3SCarlos Maiolino 
182eafc474eSCarlos Maiolino 	while (*n) {
183eafc474eSCarlos Maiolino 		parent = *n;
184eafc474eSCarlos Maiolino 		entry = rb_entry(parent, struct quota_id, node);
185eafc474eSCarlos Maiolino 
186eafc474eSCarlos Maiolino 		if (id < entry->id)
187eafc474eSCarlos Maiolino 			n = &(*n)->rb_left;
188eafc474eSCarlos Maiolino 		else if (id > entry->id)
189eafc474eSCarlos Maiolino 			n = &(*n)->rb_right;
190eafc474eSCarlos Maiolino 		else
191eafc474eSCarlos Maiolino 			goto found;
192eafc474eSCarlos Maiolino 	}
193eafc474eSCarlos Maiolino 
194eafc474eSCarlos Maiolino 	/* We don't have entry for this id yet, create it */
195eafc474eSCarlos Maiolino 	new_entry = kzalloc(sizeof(struct quota_id), GFP_NOFS);
196eafc474eSCarlos Maiolino 	if (!new_entry) {
197eafc474eSCarlos Maiolino 		ret = -ENOMEM;
198eafc474eSCarlos Maiolino 		goto out_unlock;
199eafc474eSCarlos Maiolino 	}
200eafc474eSCarlos Maiolino 
201eafc474eSCarlos Maiolino 	new_entry->id = id;
202de4c0e7cSLukas Czerner 	if (dquot->dq_id.type == USRQUOTA) {
203de4c0e7cSLukas Czerner 		new_entry->bhardlimit = sbinfo->qlimits.usrquota_bhardlimit;
204de4c0e7cSLukas Czerner 		new_entry->ihardlimit = sbinfo->qlimits.usrquota_ihardlimit;
205de4c0e7cSLukas Czerner 	} else if (dquot->dq_id.type == GRPQUOTA) {
206de4c0e7cSLukas Czerner 		new_entry->bhardlimit = sbinfo->qlimits.grpquota_bhardlimit;
207de4c0e7cSLukas Czerner 		new_entry->ihardlimit = sbinfo->qlimits.grpquota_ihardlimit;
208de4c0e7cSLukas Czerner 	}
209de4c0e7cSLukas Czerner 
210eafc474eSCarlos Maiolino 	new_node = &new_entry->node;
211eafc474eSCarlos Maiolino 	rb_link_node(new_node, parent, n);
212eafc474eSCarlos Maiolino 	rb_insert_color(new_node, (struct rb_root *)info->dqi_priv);
213eafc474eSCarlos Maiolino 	entry = new_entry;
214eafc474eSCarlos Maiolino 
215eafc474eSCarlos Maiolino found:
216eafc474eSCarlos Maiolino 	/* Load the stored limits from the tree */
217eafc474eSCarlos Maiolino 	spin_lock(&dquot->dq_dqb_lock);
218eafc474eSCarlos Maiolino 	dquot->dq_dqb.dqb_bhardlimit = entry->bhardlimit;
219eafc474eSCarlos Maiolino 	dquot->dq_dqb.dqb_bsoftlimit = entry->bsoftlimit;
220eafc474eSCarlos Maiolino 	dquot->dq_dqb.dqb_ihardlimit = entry->ihardlimit;
221eafc474eSCarlos Maiolino 	dquot->dq_dqb.dqb_isoftlimit = entry->isoftlimit;
222eafc474eSCarlos Maiolino 
223eafc474eSCarlos Maiolino 	if (!dquot->dq_dqb.dqb_bhardlimit &&
224eafc474eSCarlos Maiolino 	    !dquot->dq_dqb.dqb_bsoftlimit &&
225eafc474eSCarlos Maiolino 	    !dquot->dq_dqb.dqb_ihardlimit &&
226eafc474eSCarlos Maiolino 	    !dquot->dq_dqb.dqb_isoftlimit)
227eafc474eSCarlos Maiolino 		set_bit(DQ_FAKE_B, &dquot->dq_flags);
228eafc474eSCarlos Maiolino 	spin_unlock(&dquot->dq_dqb_lock);
229eafc474eSCarlos Maiolino 
230eafc474eSCarlos Maiolino 	/* Make sure flags update is visible after dquot has been filled */
231eafc474eSCarlos Maiolino 	smp_mb__before_atomic();
232eafc474eSCarlos Maiolino 	set_bit(DQ_ACTIVE_B, &dquot->dq_flags);
233eafc474eSCarlos Maiolino out_unlock:
234eafc474eSCarlos Maiolino 	up_write(&dqopt->dqio_sem);
235eafc474eSCarlos Maiolino 	mutex_unlock(&dquot->dq_lock);
236eafc474eSCarlos Maiolino 	return ret;
237eafc474eSCarlos Maiolino }
238eafc474eSCarlos Maiolino 
shmem_is_empty_dquot(struct dquot * dquot)239de4c0e7cSLukas Czerner static bool shmem_is_empty_dquot(struct dquot *dquot)
240de4c0e7cSLukas Czerner {
241de4c0e7cSLukas Czerner 	struct shmem_sb_info *sbinfo = dquot->dq_sb->s_fs_info;
242de4c0e7cSLukas Czerner 	qsize_t bhardlimit;
243de4c0e7cSLukas Czerner 	qsize_t ihardlimit;
244de4c0e7cSLukas Czerner 
245de4c0e7cSLukas Czerner 	if (dquot->dq_id.type == USRQUOTA) {
246de4c0e7cSLukas Czerner 		bhardlimit = sbinfo->qlimits.usrquota_bhardlimit;
247de4c0e7cSLukas Czerner 		ihardlimit = sbinfo->qlimits.usrquota_ihardlimit;
248de4c0e7cSLukas Czerner 	} else if (dquot->dq_id.type == GRPQUOTA) {
249de4c0e7cSLukas Czerner 		bhardlimit = sbinfo->qlimits.grpquota_bhardlimit;
250de4c0e7cSLukas Czerner 		ihardlimit = sbinfo->qlimits.grpquota_ihardlimit;
251de4c0e7cSLukas Czerner 	}
252de4c0e7cSLukas Czerner 
253de4c0e7cSLukas Czerner 	if (test_bit(DQ_FAKE_B, &dquot->dq_flags) ||
254de4c0e7cSLukas Czerner 		(dquot->dq_dqb.dqb_curspace == 0 &&
255de4c0e7cSLukas Czerner 		 dquot->dq_dqb.dqb_curinodes == 0 &&
256de4c0e7cSLukas Czerner 		 dquot->dq_dqb.dqb_bhardlimit == bhardlimit &&
257de4c0e7cSLukas Czerner 		 dquot->dq_dqb.dqb_ihardlimit == ihardlimit))
258de4c0e7cSLukas Czerner 		return true;
259de4c0e7cSLukas Czerner 
260de4c0e7cSLukas Czerner 	return false;
261de4c0e7cSLukas Czerner }
262eafc474eSCarlos Maiolino /*
263eafc474eSCarlos Maiolino  * Store limits from dquot in the tree unless it's fake. If it is fake
264eafc474eSCarlos Maiolino  * remove the id from the tree since there is no useful information in
265eafc474eSCarlos Maiolino  * there.
266eafc474eSCarlos Maiolino  */
shmem_release_dquot(struct dquot * dquot)267eafc474eSCarlos Maiolino static int shmem_release_dquot(struct dquot *dquot)
268eafc474eSCarlos Maiolino {
269eafc474eSCarlos Maiolino 	struct mem_dqinfo *info = sb_dqinfo(dquot->dq_sb, dquot->dq_id.type);
270*0a69b6b3SCarlos Maiolino 	struct rb_node *node;
271eafc474eSCarlos Maiolino 	qid_t id = from_kqid(&init_user_ns, dquot->dq_id);
272eafc474eSCarlos Maiolino 	struct quota_info *dqopt = sb_dqopt(dquot->dq_sb);
273eafc474eSCarlos Maiolino 	struct quota_id *entry = NULL;
274eafc474eSCarlos Maiolino 
275eafc474eSCarlos Maiolino 	mutex_lock(&dquot->dq_lock);
276eafc474eSCarlos Maiolino 	/* Check whether we are not racing with some other dqget() */
277eafc474eSCarlos Maiolino 	if (dquot_is_busy(dquot))
278eafc474eSCarlos Maiolino 		goto out_dqlock;
279eafc474eSCarlos Maiolino 
280eafc474eSCarlos Maiolino 	down_write(&dqopt->dqio_sem);
281*0a69b6b3SCarlos Maiolino 	node = ((struct rb_root *)info->dqi_priv)->rb_node;
282eafc474eSCarlos Maiolino 	while (node) {
283eafc474eSCarlos Maiolino 		entry = rb_entry(node, struct quota_id, node);
284eafc474eSCarlos Maiolino 
285eafc474eSCarlos Maiolino 		if (id < entry->id)
286eafc474eSCarlos Maiolino 			node = node->rb_left;
287eafc474eSCarlos Maiolino 		else if (id > entry->id)
288eafc474eSCarlos Maiolino 			node = node->rb_right;
289eafc474eSCarlos Maiolino 		else
290eafc474eSCarlos Maiolino 			goto found;
291eafc474eSCarlos Maiolino 	}
292eafc474eSCarlos Maiolino 
293eafc474eSCarlos Maiolino 	/* We should always find the entry in the rb tree */
294eafc474eSCarlos Maiolino 	WARN_ONCE(1, "quota id %u from dquot %p, not in rb tree!\n", id, dquot);
295eafc474eSCarlos Maiolino 	up_write(&dqopt->dqio_sem);
296eafc474eSCarlos Maiolino 	mutex_unlock(&dquot->dq_lock);
297eafc474eSCarlos Maiolino 	return -ENOENT;
298eafc474eSCarlos Maiolino 
299eafc474eSCarlos Maiolino found:
300de4c0e7cSLukas Czerner 	if (shmem_is_empty_dquot(dquot)) {
301eafc474eSCarlos Maiolino 		/* Remove entry from the tree */
302eafc474eSCarlos Maiolino 		rb_erase(&entry->node, info->dqi_priv);
303eafc474eSCarlos Maiolino 		kfree(entry);
304eafc474eSCarlos Maiolino 	} else {
305eafc474eSCarlos Maiolino 		/* Store the limits in the tree */
306eafc474eSCarlos Maiolino 		spin_lock(&dquot->dq_dqb_lock);
307eafc474eSCarlos Maiolino 		entry->bhardlimit = dquot->dq_dqb.dqb_bhardlimit;
308eafc474eSCarlos Maiolino 		entry->bsoftlimit = dquot->dq_dqb.dqb_bsoftlimit;
309eafc474eSCarlos Maiolino 		entry->ihardlimit = dquot->dq_dqb.dqb_ihardlimit;
310eafc474eSCarlos Maiolino 		entry->isoftlimit = dquot->dq_dqb.dqb_isoftlimit;
311eafc474eSCarlos Maiolino 		spin_unlock(&dquot->dq_dqb_lock);
312eafc474eSCarlos Maiolino 	}
313eafc474eSCarlos Maiolino 
314eafc474eSCarlos Maiolino 	clear_bit(DQ_ACTIVE_B, &dquot->dq_flags);
315eafc474eSCarlos Maiolino 	up_write(&dqopt->dqio_sem);
316eafc474eSCarlos Maiolino 
317eafc474eSCarlos Maiolino out_dqlock:
318eafc474eSCarlos Maiolino 	mutex_unlock(&dquot->dq_lock);
319eafc474eSCarlos Maiolino 	return 0;
320eafc474eSCarlos Maiolino }
321eafc474eSCarlos Maiolino 
shmem_mark_dquot_dirty(struct dquot * dquot)322eafc474eSCarlos Maiolino static int shmem_mark_dquot_dirty(struct dquot *dquot)
323eafc474eSCarlos Maiolino {
324eafc474eSCarlos Maiolino 	return 0;
325eafc474eSCarlos Maiolino }
326eafc474eSCarlos Maiolino 
shmem_dquot_write_info(struct super_block * sb,int type)327eafc474eSCarlos Maiolino static int shmem_dquot_write_info(struct super_block *sb, int type)
328eafc474eSCarlos Maiolino {
329eafc474eSCarlos Maiolino 	return 0;
330eafc474eSCarlos Maiolino }
331eafc474eSCarlos Maiolino 
332eafc474eSCarlos Maiolino static const struct quota_format_ops shmem_format_ops = {
333eafc474eSCarlos Maiolino 	.check_quota_file	= shmem_check_quota_file,
334eafc474eSCarlos Maiolino 	.read_file_info		= shmem_read_file_info,
335eafc474eSCarlos Maiolino 	.write_file_info	= shmem_write_file_info,
336eafc474eSCarlos Maiolino 	.free_file_info		= shmem_free_file_info,
337eafc474eSCarlos Maiolino };
338eafc474eSCarlos Maiolino 
339eafc474eSCarlos Maiolino struct quota_format_type shmem_quota_format = {
340eafc474eSCarlos Maiolino 	.qf_fmt_id = QFMT_SHMEM,
341eafc474eSCarlos Maiolino 	.qf_ops = &shmem_format_ops,
342eafc474eSCarlos Maiolino 	.qf_owner = THIS_MODULE
343eafc474eSCarlos Maiolino };
344eafc474eSCarlos Maiolino 
345eafc474eSCarlos Maiolino const struct dquot_operations shmem_quota_operations = {
346eafc474eSCarlos Maiolino 	.acquire_dquot		= shmem_acquire_dquot,
347eafc474eSCarlos Maiolino 	.release_dquot		= shmem_release_dquot,
348eafc474eSCarlos Maiolino 	.alloc_dquot		= dquot_alloc,
349eafc474eSCarlos Maiolino 	.destroy_dquot		= dquot_destroy,
350eafc474eSCarlos Maiolino 	.write_info		= shmem_dquot_write_info,
351eafc474eSCarlos Maiolino 	.mark_dirty		= shmem_mark_dquot_dirty,
352eafc474eSCarlos Maiolino 	.get_next_id		= shmem_get_next_id,
353eafc474eSCarlos Maiolino };
354eafc474eSCarlos Maiolino #endif /* CONFIG_TMPFS_QUOTA */
355