Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/fs/coda/inode.c
26278 views
1
// SPDX-License-Identifier: GPL-2.0
2
/*
3
* Super block/filesystem wide operations
4
*
5
* Copyright (C) 1996 Peter J. Braam <[email protected]> and
6
* Michael Callahan <[email protected]>
7
*
8
* Rewritten for Linux 2.1. Peter Braam <[email protected]>
9
* Copyright (C) Carnegie Mellon University
10
*/
11
12
#include <linux/module.h>
13
#include <linux/kernel.h>
14
#include <linux/mm.h>
15
#include <linux/string.h>
16
#include <linux/stat.h>
17
#include <linux/errno.h>
18
#include <linux/unistd.h>
19
#include <linux/mutex.h>
20
#include <linux/spinlock.h>
21
#include <linux/file.h>
22
#include <linux/vfs.h>
23
#include <linux/slab.h>
24
#include <linux/pid_namespace.h>
25
#include <linux/uaccess.h>
26
#include <linux/fs.h>
27
#include <linux/fs_context.h>
28
#include <linux/fs_parser.h>
29
#include <linux/vmalloc.h>
30
31
#include <linux/coda.h>
32
#include "coda_psdev.h"
33
#include "coda_linux.h"
34
#include "coda_cache.h"
35
36
#include "coda_int.h"
37
38
/* VFS super_block ops */
39
static void coda_evict_inode(struct inode *);
40
static void coda_put_super(struct super_block *);
41
static int coda_statfs(struct dentry *dentry, struct kstatfs *buf);
42
43
static struct kmem_cache * coda_inode_cachep;
44
45
static struct inode *coda_alloc_inode(struct super_block *sb)
46
{
47
struct coda_inode_info *ei;
48
ei = alloc_inode_sb(sb, coda_inode_cachep, GFP_KERNEL);
49
if (!ei)
50
return NULL;
51
memset(&ei->c_fid, 0, sizeof(struct CodaFid));
52
ei->c_flags = 0;
53
ei->c_uid = GLOBAL_ROOT_UID;
54
ei->c_cached_perm = 0;
55
spin_lock_init(&ei->c_lock);
56
return &ei->vfs_inode;
57
}
58
59
static void coda_free_inode(struct inode *inode)
60
{
61
kmem_cache_free(coda_inode_cachep, ITOC(inode));
62
}
63
64
static void init_once(void *foo)
65
{
66
struct coda_inode_info *ei = (struct coda_inode_info *) foo;
67
68
inode_init_once(&ei->vfs_inode);
69
}
70
71
int __init coda_init_inodecache(void)
72
{
73
coda_inode_cachep = kmem_cache_create("coda_inode_cache",
74
sizeof(struct coda_inode_info), 0,
75
SLAB_RECLAIM_ACCOUNT | SLAB_ACCOUNT,
76
init_once);
77
if (coda_inode_cachep == NULL)
78
return -ENOMEM;
79
return 0;
80
}
81
82
void coda_destroy_inodecache(void)
83
{
84
/*
85
* Make sure all delayed rcu free inodes are flushed before we
86
* destroy cache.
87
*/
88
rcu_barrier();
89
kmem_cache_destroy(coda_inode_cachep);
90
}
91
92
static int coda_reconfigure(struct fs_context *fc)
93
{
94
sync_filesystem(fc->root->d_sb);
95
fc->sb_flags |= SB_NOATIME;
96
return 0;
97
}
98
99
/* exported operations */
100
static const struct super_operations coda_super_operations =
101
{
102
.alloc_inode = coda_alloc_inode,
103
.free_inode = coda_free_inode,
104
.evict_inode = coda_evict_inode,
105
.put_super = coda_put_super,
106
.statfs = coda_statfs,
107
};
108
109
struct coda_fs_context {
110
int idx;
111
};
112
113
enum {
114
Opt_fd,
115
};
116
117
static const struct fs_parameter_spec coda_param_specs[] = {
118
fsparam_fd ("fd", Opt_fd),
119
{}
120
};
121
122
static int coda_set_idx(struct fs_context *fc, struct file *file)
123
{
124
struct coda_fs_context *ctx = fc->fs_private;
125
struct inode *inode;
126
int idx;
127
128
inode = file_inode(file);
129
if (!S_ISCHR(inode->i_mode) || imajor(inode) != CODA_PSDEV_MAJOR) {
130
return invalf(fc, "coda: Not coda psdev");
131
}
132
idx = iminor(inode);
133
if (idx < 0 || idx >= MAX_CODADEVS)
134
return invalf(fc, "coda: Bad minor number");
135
ctx->idx = idx;
136
return 0;
137
}
138
139
static int coda_parse_fd(struct fs_context *fc, struct fs_parameter *param,
140
struct fs_parse_result *result)
141
{
142
struct file *file;
143
int err;
144
145
if (param->type == fs_value_is_file) {
146
file = param->file;
147
param->file = NULL;
148
} else {
149
file = fget(result->uint_32);
150
}
151
if (!file)
152
return -EBADF;
153
154
err = coda_set_idx(fc, file);
155
fput(file);
156
return err;
157
}
158
159
static int coda_parse_param(struct fs_context *fc, struct fs_parameter *param)
160
{
161
struct fs_parse_result result;
162
int opt;
163
164
opt = fs_parse(fc, coda_param_specs, param, &result);
165
if (opt < 0)
166
return opt;
167
168
switch (opt) {
169
case Opt_fd:
170
return coda_parse_fd(fc, param, &result);
171
}
172
173
return 0;
174
}
175
176
/*
177
* Parse coda's binary mount data form. We ignore any errors and go with index
178
* 0 if we get one for backward compatibility.
179
*/
180
static int coda_parse_monolithic(struct fs_context *fc, void *_data)
181
{
182
struct file *file;
183
struct coda_mount_data *data = _data;
184
185
if (!data)
186
return invalf(fc, "coda: Bad mount data");
187
188
if (data->version != CODA_MOUNT_VERSION)
189
return invalf(fc, "coda: Bad mount version");
190
191
file = fget(data->fd);
192
if (file) {
193
coda_set_idx(fc, file);
194
fput(file);
195
}
196
return 0;
197
}
198
199
static int coda_fill_super(struct super_block *sb, struct fs_context *fc)
200
{
201
struct coda_fs_context *ctx = fc->fs_private;
202
struct inode *root = NULL;
203
struct venus_comm *vc;
204
struct CodaFid fid;
205
int error;
206
207
infof(fc, "coda: device index: %i\n", ctx->idx);
208
209
vc = &coda_comms[ctx->idx];
210
mutex_lock(&vc->vc_mutex);
211
212
if (!vc->vc_inuse) {
213
errorf(fc, "coda: No pseudo device");
214
error = -EINVAL;
215
goto unlock_out;
216
}
217
218
if (vc->vc_sb) {
219
errorf(fc, "coda: Device already mounted");
220
error = -EBUSY;
221
goto unlock_out;
222
}
223
224
vc->vc_sb = sb;
225
mutex_unlock(&vc->vc_mutex);
226
227
sb->s_fs_info = vc;
228
sb->s_flags |= SB_NOATIME;
229
sb->s_blocksize = 4096; /* XXXXX what do we put here?? */
230
sb->s_blocksize_bits = 12;
231
sb->s_magic = CODA_SUPER_MAGIC;
232
sb->s_op = &coda_super_operations;
233
set_default_d_op(sb, &coda_dentry_operations);
234
sb->s_time_gran = 1;
235
sb->s_time_min = S64_MIN;
236
sb->s_time_max = S64_MAX;
237
238
error = super_setup_bdi(sb);
239
if (error)
240
goto error;
241
242
/* get root fid from Venus: this needs the root inode */
243
error = venus_rootfid(sb, &fid);
244
if ( error ) {
245
pr_warn("%s: coda_get_rootfid failed with %d\n",
246
__func__, error);
247
goto error;
248
}
249
pr_info("%s: rootfid is %s\n", __func__, coda_f2s(&fid));
250
251
/* make root inode */
252
root = coda_cnode_make(&fid, sb);
253
if (IS_ERR(root)) {
254
error = PTR_ERR(root);
255
pr_warn("Failure of coda_cnode_make for root: error %d\n",
256
error);
257
goto error;
258
}
259
260
pr_info("%s: rootinode is %ld dev %s\n",
261
__func__, root->i_ino, root->i_sb->s_id);
262
sb->s_root = d_make_root(root);
263
if (!sb->s_root) {
264
error = -EINVAL;
265
goto error;
266
}
267
return 0;
268
269
error:
270
mutex_lock(&vc->vc_mutex);
271
vc->vc_sb = NULL;
272
sb->s_fs_info = NULL;
273
unlock_out:
274
mutex_unlock(&vc->vc_mutex);
275
return error;
276
}
277
278
static void coda_put_super(struct super_block *sb)
279
{
280
struct venus_comm *vcp = coda_vcp(sb);
281
mutex_lock(&vcp->vc_mutex);
282
vcp->vc_sb = NULL;
283
sb->s_fs_info = NULL;
284
mutex_unlock(&vcp->vc_mutex);
285
mutex_destroy(&vcp->vc_mutex);
286
287
pr_info("Bye bye.\n");
288
}
289
290
static void coda_evict_inode(struct inode *inode)
291
{
292
truncate_inode_pages_final(&inode->i_data);
293
clear_inode(inode);
294
coda_cache_clear_inode(inode);
295
}
296
297
int coda_getattr(struct mnt_idmap *idmap, const struct path *path,
298
struct kstat *stat, u32 request_mask, unsigned int flags)
299
{
300
int err = coda_revalidate_inode(d_inode(path->dentry));
301
if (!err)
302
generic_fillattr(&nop_mnt_idmap, request_mask,
303
d_inode(path->dentry), stat);
304
return err;
305
}
306
307
int coda_setattr(struct mnt_idmap *idmap, struct dentry *de,
308
struct iattr *iattr)
309
{
310
struct inode *inode = d_inode(de);
311
struct coda_vattr vattr;
312
int error;
313
314
memset(&vattr, 0, sizeof(vattr));
315
316
inode_set_ctime_current(inode);
317
coda_iattr_to_vattr(iattr, &vattr);
318
vattr.va_type = C_VNON; /* cannot set type */
319
320
/* Venus is responsible for truncating the container-file!!! */
321
error = venus_setattr(inode->i_sb, coda_i2f(inode), &vattr);
322
323
if (!error) {
324
coda_vattr_to_iattr(inode, &vattr);
325
coda_cache_clear_inode(inode);
326
}
327
return error;
328
}
329
330
const struct inode_operations coda_file_inode_operations = {
331
.permission = coda_permission,
332
.getattr = coda_getattr,
333
.setattr = coda_setattr,
334
};
335
336
static int coda_statfs(struct dentry *dentry, struct kstatfs *buf)
337
{
338
int error;
339
340
error = venus_statfs(dentry, buf);
341
342
if (error) {
343
/* fake something like AFS does */
344
buf->f_blocks = 9000000;
345
buf->f_bfree = 9000000;
346
buf->f_bavail = 9000000;
347
buf->f_files = 9000000;
348
buf->f_ffree = 9000000;
349
}
350
351
/* and fill in the rest */
352
buf->f_type = CODA_SUPER_MAGIC;
353
buf->f_bsize = 4096;
354
buf->f_namelen = CODA_MAXNAMLEN;
355
356
return 0;
357
}
358
359
static int coda_get_tree(struct fs_context *fc)
360
{
361
if (task_active_pid_ns(current) != &init_pid_ns)
362
return -EINVAL;
363
364
return get_tree_nodev(fc, coda_fill_super);
365
}
366
367
static void coda_free_fc(struct fs_context *fc)
368
{
369
kfree(fc->fs_private);
370
}
371
372
static const struct fs_context_operations coda_context_ops = {
373
.free = coda_free_fc,
374
.parse_param = coda_parse_param,
375
.parse_monolithic = coda_parse_monolithic,
376
.get_tree = coda_get_tree,
377
.reconfigure = coda_reconfigure,
378
};
379
380
static int coda_init_fs_context(struct fs_context *fc)
381
{
382
struct coda_fs_context *ctx;
383
384
ctx = kzalloc(sizeof(struct coda_fs_context), GFP_KERNEL);
385
if (!ctx)
386
return -ENOMEM;
387
388
fc->fs_private = ctx;
389
fc->ops = &coda_context_ops;
390
return 0;
391
}
392
393
struct file_system_type coda_fs_type = {
394
.owner = THIS_MODULE,
395
.name = "coda",
396
.init_fs_context = coda_init_fs_context,
397
.parameters = coda_param_specs,
398
.kill_sb = kill_anon_super,
399
.fs_flags = FS_BINARY_MOUNTDATA,
400
};
401
MODULE_ALIAS_FS("coda");
402
403
404