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*c7077f43SCarlos 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*c7077f43SCarlos 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*c7077f43SCarlos 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*c7077f43SCarlos Maiolino n = &((struct rb_root *)info->dqi_priv)->rb_node;
181*c7077f43SCarlos 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*c7077f43SCarlos 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*c7077f43SCarlos 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