Blame view

fs/sysv/inode.c 9.26 KB
b24413180   Greg Kroah-Hartman   License cleanup: ...
1
  // SPDX-License-Identifier: GPL-2.0
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
  /*
   *  linux/fs/sysv/inode.c
   *
   *  minix/inode.c
   *  Copyright (C) 1991, 1992  Linus Torvalds
   *
   *  xenix/inode.c
   *  Copyright (C) 1992  Doug Evans
   *
   *  coh/inode.c
   *  Copyright (C) 1993  Pascal Haible, Bruno Haible
   *
   *  sysv/inode.c
   *  Copyright (C) 1993  Paul B. Monday
   *
   *  sysv/inode.c
   *  Copyright (C) 1993  Bruno Haible
   *  Copyright (C) 1997, 1998  Krzysztof G. Baranowski
   *
   *  This file contains code for allocating/freeing inodes and for read/writing
   *  the superblock.
   */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
24
25
26
27
28
  #include <linux/highuid.h>
  #include <linux/slab.h>
  #include <linux/init.h>
  #include <linux/buffer_head.h>
  #include <linux/vfs.h>
a9185b41a   Christoph Hellwig   pass writeback_co...
29
  #include <linux/writeback.h>
21acaf8e8   Duane Griffin   sysv: ensure fast...
30
  #include <linux/namei.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
31
32
  #include <asm/byteorder.h>
  #include "sysv.h"
ad43ffdee   Christoph Hellwig   sysv: add ->sync_fs
33
  static int sysv_sync_fs(struct super_block *sb, int wait)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
34
35
36
  {
  	struct sysv_sb_info *sbi = SYSV_SB(sb);
  	unsigned long time = get_seconds(), old_time;
c07cb01c4   Marco Stornelli   sysv: drop lock/u...
37
  	mutex_lock(&sbi->s_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
38
39
40
41
42
43
44
45
46
47
48
49
50
  
  	/*
  	 * If we are going to write out the super block,
  	 * then attach current time stamp.
  	 * But if the filesystem was marked clean, keep it clean.
  	 */
  	old_time = fs32_to_cpu(sbi, *sbi->s_sb_time);
  	if (sbi->s_type == FSTYPE_SYSV4) {
  		if (*sbi->s_sb_state == cpu_to_fs32(sbi, 0x7c269d38 - old_time))
  			*sbi->s_sb_state = cpu_to_fs32(sbi, 0x7c269d38 - time);
  		*sbi->s_sb_time = cpu_to_fs32(sbi, time);
  		mark_buffer_dirty(sbi->s_bh2);
  	}
ad43ffdee   Christoph Hellwig   sysv: add ->sync_fs
51

c07cb01c4   Marco Stornelli   sysv: drop lock/u...
52
  	mutex_unlock(&sbi->s_lock);
ad43ffdee   Christoph Hellwig   sysv: add ->sync_fs
53
54
55
  
  	return 0;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
56
57
58
  static int sysv_remount(struct super_block *sb, int *flags, char *data)
  {
  	struct sysv_sb_info *sbi = SYSV_SB(sb);
eee458936   Artem Bityutskiy   fs/sysv: remove a...
59

02b9984d6   Theodore Ts'o   fs: push sync_fil...
60
  	sync_filesystem(sb);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
61
62
  	if (sbi->s_forced_ro)
  		*flags |= MS_RDONLY;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
63
64
65
66
67
68
  	return 0;
  }
  
  static void sysv_put_super(struct super_block *sb)
  {
  	struct sysv_sb_info *sbi = SYSV_SB(sb);
bc98a42c1   David Howells   VFS: Convert sb->...
69
  	if (!sb_rdonly(sb)) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
70
71
72
73
74
75
76
77
78
79
80
81
  		/* XXX ext2 also updates the state here */
  		mark_buffer_dirty(sbi->s_bh1);
  		if (sbi->s_bh1 != sbi->s_bh2)
  			mark_buffer_dirty(sbi->s_bh2);
  	}
  
  	brelse(sbi->s_bh1);
  	if (sbi->s_bh1 != sbi->s_bh2)
  		brelse(sbi->s_bh2);
  
  	kfree(sbi);
  }
726c33422   David Howells   [PATCH] VFS: Perm...
82
  static int sysv_statfs(struct dentry *dentry, struct kstatfs *buf)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
83
  {
726c33422   David Howells   [PATCH] VFS: Perm...
84
  	struct super_block *sb = dentry->d_sb;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
85
  	struct sysv_sb_info *sbi = SYSV_SB(sb);
1c5b45411   Coly Li   fs/sysv: return f...
86
  	u64 id = huge_encode_dev(sb->s_bdev->bd_dev);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
87
88
89
90
91
92
93
94
  
  	buf->f_type = sb->s_magic;
  	buf->f_bsize = sb->s_blocksize;
  	buf->f_blocks = sbi->s_ndatazones;
  	buf->f_bavail = buf->f_bfree = sysv_count_free_blocks(sb);
  	buf->f_files = sbi->s_ninodes;
  	buf->f_ffree = sysv_count_free_inodes(sb);
  	buf->f_namelen = SYSV_NAMELEN;
1c5b45411   Coly Li   fs/sysv: return f...
95
96
  	buf->f_fsid.val[0] = (u32)id;
  	buf->f_fsid.val[1] = (u32)(id >> 32);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
  	return 0;
  }
  
  /* 
   * NXI <-> N0XI for PDP, XIN <-> XIN0 for le32, NIX <-> 0NIX for be32
   */
  static inline void read3byte(struct sysv_sb_info *sbi,
  	unsigned char * from, unsigned char * to)
  {
  	if (sbi->s_bytesex == BYTESEX_PDP) {
  		to[0] = from[0];
  		to[1] = 0;
  		to[2] = from[1];
  		to[3] = from[2];
  	} else if (sbi->s_bytesex == BYTESEX_LE) {
  		to[0] = from[0];
  		to[1] = from[1];
  		to[2] = from[2];
  		to[3] = 0;
  	} else {
  		to[0] = 0;
  		to[1] = from[0];
  		to[2] = from[1];
  		to[3] = from[2];
  	}
  }
  
  static inline void write3byte(struct sysv_sb_info *sbi,
  	unsigned char * from, unsigned char * to)
  {
  	if (sbi->s_bytesex == BYTESEX_PDP) {
  		to[0] = from[0];
  		to[1] = from[2];
  		to[2] = from[3];
  	} else if (sbi->s_bytesex == BYTESEX_LE) {
  		to[0] = from[0];
  		to[1] = from[1];
  		to[2] = from[2];
  	} else {
  		to[0] = from[1];
  		to[1] = from[2];
  		to[2] = from[3];
  	}
  }
c5ef1c42c   Arjan van de Ven   [PATCH] mark stru...
141
  static const struct inode_operations sysv_symlink_inode_operations = {
6b2553918   Al Viro   replace ->follow_...
142
  	.get_link	= page_get_link,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
143
144
145
146
147
148
149
150
151
152
153
154
155
156
  	.getattr	= sysv_getattr,
  };
  
  void sysv_set_inode(struct inode *inode, dev_t rdev)
  {
  	if (S_ISREG(inode->i_mode)) {
  		inode->i_op = &sysv_file_inode_operations;
  		inode->i_fop = &sysv_file_operations;
  		inode->i_mapping->a_ops = &sysv_aops;
  	} else if (S_ISDIR(inode->i_mode)) {
  		inode->i_op = &sysv_dir_inode_operations;
  		inode->i_fop = &sysv_dir_operations;
  		inode->i_mapping->a_ops = &sysv_aops;
  	} else if (S_ISLNK(inode->i_mode)) {
0ebf7f10d   Al Viro   fix sysvfs symlinks
157
  		inode->i_op = &sysv_symlink_inode_operations;
21fc61c73   Al Viro   don't put symlink...
158
  		inode_nohighmem(inode);
0ebf7f10d   Al Viro   fix sysvfs symlinks
159
  		inode->i_mapping->a_ops = &sysv_aops;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
160
161
162
  	} else
  		init_special_inode(inode, inode->i_mode, rdev);
  }
b8e1343f6   David Howells   iget: stop the SY...
163
  struct inode *sysv_iget(struct super_block *sb, unsigned int ino)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
164
  {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
165
166
167
168
  	struct sysv_sb_info * sbi = SYSV_SB(sb);
  	struct buffer_head * bh;
  	struct sysv_inode * raw_inode;
  	struct sysv_inode_info * si;
b8e1343f6   David Howells   iget: stop the SY...
169
170
  	struct inode *inode;
  	unsigned int block;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
171
172
173
174
  
  	if (!ino || ino > sbi->s_ninodes) {
  		printk("Bad inode number on dev %s: %d is out of range
  ",
b8e1343f6   David Howells   iget: stop the SY...
175
176
  		       sb->s_id, ino);
  		return ERR_PTR(-EIO);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
177
  	}
b8e1343f6   David Howells   iget: stop the SY...
178
179
180
181
182
183
  
  	inode = iget_locked(sb, ino);
  	if (!inode)
  		return ERR_PTR(-ENOMEM);
  	if (!(inode->i_state & I_NEW))
  		return inode;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
184
185
186
187
188
189
190
191
192
  	raw_inode = sysv_raw_inode(sb, ino, &bh);
  	if (!raw_inode) {
  		printk("Major problem: unable to read inode from dev %s
  ",
  		       inode->i_sb->s_id);
  		goto bad_inode;
  	}
  	/* SystemV FS: kludge permissions if ino==SYSV_ROOT_INO ?? */
  	inode->i_mode = fs16_to_cpu(sbi, raw_inode->i_mode);
a726ecce7   Eric W. Biederman   userns: Convert t...
193
194
  	i_uid_write(inode, (uid_t)fs16_to_cpu(sbi, raw_inode->i_uid));
  	i_gid_write(inode, (gid_t)fs16_to_cpu(sbi, raw_inode->i_gid));
bfe868486   Miklos Szeredi   filesystems: add ...
195
  	set_nlink(inode, fs16_to_cpu(sbi, raw_inode->i_nlink));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
196
197
198
199
200
201
202
  	inode->i_size = fs32_to_cpu(sbi, raw_inode->i_size);
  	inode->i_atime.tv_sec = fs32_to_cpu(sbi, raw_inode->i_atime);
  	inode->i_mtime.tv_sec = fs32_to_cpu(sbi, raw_inode->i_mtime);
  	inode->i_ctime.tv_sec = fs32_to_cpu(sbi, raw_inode->i_ctime);
  	inode->i_ctime.tv_nsec = 0;
  	inode->i_atime.tv_nsec = 0;
  	inode->i_mtime.tv_nsec = 0;
ba52de123   Theodore Ts'o   [PATCH] inode-die...
203
  	inode->i_blocks = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
204
205
206
207
208
209
210
211
212
213
214
215
  
  	si = SYSV_I(inode);
  	for (block = 0; block < 10+1+1+1; block++)
  		read3byte(sbi, &raw_inode->i_data[3*block],
  				(u8 *)&si->i_data[block]);
  	brelse(bh);
  	si->i_dir_start_lookup = 0;
  	if (S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode))
  		sysv_set_inode(inode,
  			       old_decode_dev(fs32_to_cpu(sbi, si->i_data[0])));
  	else
  		sysv_set_inode(inode, 0);
b8e1343f6   David Howells   iget: stop the SY...
216
217
  	unlock_new_inode(inode);
  	return inode;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
218
219
  
  bad_inode:
b8e1343f6   David Howells   iget: stop the SY...
220
221
  	iget_failed(inode);
  	return ERR_PTR(-EIO);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
222
  }
a9185b41a   Christoph Hellwig   pass writeback_co...
223
  static int __sysv_write_inode(struct inode *inode, int wait)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
224
225
226
227
228
229
230
  {
  	struct super_block * sb = inode->i_sb;
  	struct sysv_sb_info * sbi = SYSV_SB(sb);
  	struct buffer_head * bh;
  	struct sysv_inode * raw_inode;
  	struct sysv_inode_info * si;
  	unsigned int ino, block;
05459ca81   Al Viro   repair sysv_write...
231
  	int err = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
232
233
234
235
236
237
  
  	ino = inode->i_ino;
  	if (!ino || ino > sbi->s_ninodes) {
  		printk("Bad inode number on dev %s: %d is out of range
  ",
  		       inode->i_sb->s_id, ino);
05459ca81   Al Viro   repair sysv_write...
238
  		return -EIO;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
239
240
241
242
243
  	}
  	raw_inode = sysv_raw_inode(sb, ino, &bh);
  	if (!raw_inode) {
  		printk("unable to read i-node block
  ");
05459ca81   Al Viro   repair sysv_write...
244
  		return -EIO;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
245
246
247
  	}
  
  	raw_inode->i_mode = cpu_to_fs16(sbi, inode->i_mode);
a726ecce7   Eric W. Biederman   userns: Convert t...
248
249
  	raw_inode->i_uid = cpu_to_fs16(sbi, fs_high2lowuid(i_uid_read(inode)));
  	raw_inode->i_gid = cpu_to_fs16(sbi, fs_high2lowgid(i_gid_read(inode)));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
250
251
252
253
254
255
256
257
258
259
260
261
262
  	raw_inode->i_nlink = cpu_to_fs16(sbi, inode->i_nlink);
  	raw_inode->i_size = cpu_to_fs32(sbi, inode->i_size);
  	raw_inode->i_atime = cpu_to_fs32(sbi, inode->i_atime.tv_sec);
  	raw_inode->i_mtime = cpu_to_fs32(sbi, inode->i_mtime.tv_sec);
  	raw_inode->i_ctime = cpu_to_fs32(sbi, inode->i_ctime.tv_sec);
  
  	si = SYSV_I(inode);
  	if (S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode))
  		si->i_data[0] = cpu_to_fs32(sbi, old_encode_dev(inode->i_rdev));
  	for (block = 0; block < 10+1+1+1; block++)
  		write3byte(sbi, (u8 *)&si->i_data[block],
  			&raw_inode->i_data[3*block]);
  	mark_buffer_dirty(bh);
05459ca81   Al Viro   repair sysv_write...
263
264
265
266
267
268
269
270
271
  	if (wait) {
                  sync_dirty_buffer(bh);
                  if (buffer_req(bh) && !buffer_uptodate(bh)) {
                          printk ("IO error syncing sysv inode [%s:%08x]
  ",
                                  sb->s_id, ino);
                          err = -EIO;
                  }
          }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
272
  	brelse(bh);
2ac368e8d   YueHaibing   sysv: return 'err...
273
  	return err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
274
  }
a9185b41a   Christoph Hellwig   pass writeback_co...
275
276
277
278
  int sysv_write_inode(struct inode *inode, struct writeback_control *wbc)
  {
  	return __sysv_write_inode(inode, wbc->sync_mode == WB_SYNC_ALL);
  }
05459ca81   Al Viro   repair sysv_write...
279
  int sysv_sync_inode(struct inode *inode)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
280
  {
a9185b41a   Christoph Hellwig   pass writeback_co...
281
  	return __sysv_write_inode(inode, 1);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
282
  }
d299eadc0   Al Viro   switch sysv to ->...
283
  static void sysv_evict_inode(struct inode *inode)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
284
  {
91b0abe36   Johannes Weiner   mm + fs: store sh...
285
  	truncate_inode_pages_final(&inode->i_data);
d299eadc0   Al Viro   switch sysv to ->...
286
287
288
289
290
  	if (!inode->i_nlink) {
  		inode->i_size = 0;
  		sysv_truncate(inode);
  	}
  	invalidate_inode_buffers(inode);
dbd5768f8   Jan Kara   vfs: Rename end_w...
291
  	clear_inode(inode);
d299eadc0   Al Viro   switch sysv to ->...
292
293
  	if (!inode->i_nlink)
  		sysv_free_inode(inode);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
294
  }
e18b890bb   Christoph Lameter   [PATCH] slab: rem...
295
  static struct kmem_cache *sysv_inode_cachep;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
296
297
298
299
  
  static struct inode *sysv_alloc_inode(struct super_block *sb)
  {
  	struct sysv_inode_info *si;
e94b17660   Christoph Lameter   [PATCH] slab: rem...
300
  	si = kmem_cache_alloc(sysv_inode_cachep, GFP_KERNEL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
301
302
303
304
  	if (!si)
  		return NULL;
  	return &si->vfs_inode;
  }
fa0d7e3de   Nick Piggin   fs: icache RCU fr...
305
  static void sysv_i_callback(struct rcu_head *head)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
306
  {
fa0d7e3de   Nick Piggin   fs: icache RCU fr...
307
  	struct inode *inode = container_of(head, struct inode, i_rcu);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
308
309
  	kmem_cache_free(sysv_inode_cachep, SYSV_I(inode));
  }
fa0d7e3de   Nick Piggin   fs: icache RCU fr...
310
311
312
313
  static void sysv_destroy_inode(struct inode *inode)
  {
  	call_rcu(&inode->i_rcu, sysv_i_callback);
  }
51cc50685   Alexey Dobriyan   SL*B: drop kmem c...
314
  static void init_once(void *p)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
315
316
  {
  	struct sysv_inode_info *si = (struct sysv_inode_info *)p;
a35afb830   Christoph Lameter   Remove SLAB_CTOR_...
317
  	inode_init_once(&si->vfs_inode);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
318
  }
ee9b6d61a   Josef 'Jeff' Sipek   [PATCH] Mark stru...
319
  const struct super_operations sysv_sops = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
320
321
  	.alloc_inode	= sysv_alloc_inode,
  	.destroy_inode	= sysv_destroy_inode,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
322
  	.write_inode	= sysv_write_inode,
d299eadc0   Al Viro   switch sysv to ->...
323
  	.evict_inode	= sysv_evict_inode,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
324
  	.put_super	= sysv_put_super,
ad43ffdee   Christoph Hellwig   sysv: add ->sync_fs
325
  	.sync_fs	= sysv_sync_fs,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
326
327
328
329
330
331
332
333
  	.remount_fs	= sysv_remount,
  	.statfs		= sysv_statfs,
  };
  
  int __init sysv_init_icache(void)
  {
  	sysv_inode_cachep = kmem_cache_create("sysv_inode_cache",
  			sizeof(struct sysv_inode_info), 0,
5d097056c   Vladimir Davydov   kmemcg: account c...
334
  			SLAB_RECLAIM_ACCOUNT|SLAB_MEM_SPREAD|SLAB_ACCOUNT,
20c2df83d   Paul Mundt   mm: Remove slab d...
335
  			init_once);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
336
337
338
339
340
341
342
  	if (!sysv_inode_cachep)
  		return -ENOMEM;
  	return 0;
  }
  
  void sysv_destroy_icache(void)
  {
8c0a85377   Kirill A. Shutemov   fs: push rcu_barr...
343
344
345
346
347
  	/*
  	 * Make sure all delayed rcu free inodes are flushed before we
  	 * destroy cache.
  	 */
  	rcu_barrier();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
348
349
  	kmem_cache_destroy(sysv_inode_cachep);
  }