inode.c 9.3 KB
Newer Older
L
Linus Torvalds 已提交
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
/*
 *  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.
 */

#include <linux/highuid.h>
#include <linux/slab.h>
#include <linux/init.h>
#include <linux/buffer_head.h>
#include <linux/vfs.h>
29
#include <linux/writeback.h>
30
#include <linux/namei.h>
L
Linus Torvalds 已提交
31 32 33
#include <asm/byteorder.h>
#include "sysv.h"

C
Christoph Hellwig 已提交
34
static int sysv_sync_fs(struct super_block *sb, int wait)
L
Linus Torvalds 已提交
35 36 37 38
{
	struct sysv_sb_info *sbi = SYSV_SB(sb);
	unsigned long time = get_seconds(), old_time;

M
Marco Stornelli 已提交
39
	mutex_lock(&sbi->s_lock);
L
Linus Torvalds 已提交
40 41 42 43 44 45 46 47 48 49 50 51 52

	/*
	 * 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);
	}
C
Christoph Hellwig 已提交
53

M
Marco Stornelli 已提交
54
	mutex_unlock(&sbi->s_lock);
C
Christoph Hellwig 已提交
55 56 57 58

	return 0;
}

L
Linus Torvalds 已提交
59 60 61
static int sysv_remount(struct super_block *sb, int *flags, char *data)
{
	struct sysv_sb_info *sbi = SYSV_SB(sb);
62

63
	sync_filesystem(sb);
L
Linus Torvalds 已提交
64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86
	if (sbi->s_forced_ro)
		*flags |= MS_RDONLY;
	return 0;
}

static void sysv_put_super(struct super_block *sb)
{
	struct sysv_sb_info *sbi = SYSV_SB(sb);

	if (!(sb->s_flags & MS_RDONLY)) {
		/* 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);
}

87
static int sysv_statfs(struct dentry *dentry, struct kstatfs *buf)
L
Linus Torvalds 已提交
88
{
89
	struct super_block *sb = dentry->d_sb;
L
Linus Torvalds 已提交
90
	struct sysv_sb_info *sbi = SYSV_SB(sb);
C
Coly Li 已提交
91
	u64 id = huge_encode_dev(sb->s_bdev->bd_dev);
L
Linus Torvalds 已提交
92 93 94 95 96 97 98 99

	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;
C
Coly Li 已提交
100 101
	buf->f_fsid.val[0] = (u32)id;
	buf->f_fsid.val[1] = (u32)(id >> 32);
L
Linus Torvalds 已提交
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 141 142 143 144 145 146
	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];
	}
}

147
static const struct inode_operations sysv_symlink_inode_operations = {
L
Linus Torvalds 已提交
148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164
	.readlink	= generic_readlink,
	.follow_link	= page_follow_link_light,
	.put_link	= page_put_link,
	.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)) {
A
Al Viro 已提交
165 166
		inode->i_op = &sysv_symlink_inode_operations;
		inode->i_mapping->a_ops = &sysv_aops;
L
Linus Torvalds 已提交
167 168 169 170
	} else
		init_special_inode(inode, inode->i_mode, rdev);
}

171
struct inode *sysv_iget(struct super_block *sb, unsigned int ino)
L
Linus Torvalds 已提交
172 173 174 175 176
{
	struct sysv_sb_info * sbi = SYSV_SB(sb);
	struct buffer_head * bh;
	struct sysv_inode * raw_inode;
	struct sysv_inode_info * si;
177 178
	struct inode *inode;
	unsigned int block;
L
Linus Torvalds 已提交
179 180 181

	if (!ino || ino > sbi->s_ninodes) {
		printk("Bad inode number on dev %s: %d is out of range\n",
182 183
		       sb->s_id, ino);
		return ERR_PTR(-EIO);
L
Linus Torvalds 已提交
184
	}
185 186 187 188 189 190 191

	inode = iget_locked(sb, ino);
	if (!inode)
		return ERR_PTR(-ENOMEM);
	if (!(inode->i_state & I_NEW))
		return inode;

L
Linus Torvalds 已提交
192 193 194 195 196 197 198 199
	raw_inode = sysv_raw_inode(sb, ino, &bh);
	if (!raw_inode) {
		printk("Major problem: unable to read inode from dev %s\n",
		       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);
200 201
	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));
M
Miklos Szeredi 已提交
202
	set_nlink(inode, fs16_to_cpu(sbi, raw_inode->i_nlink));
L
Linus Torvalds 已提交
203 204 205 206 207 208 209
	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;
210
	inode->i_blocks = 0;
L
Linus Torvalds 已提交
211 212 213 214 215 216 217 218 219 220 221 222

	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);
223 224
	unlock_new_inode(inode);
	return inode;
L
Linus Torvalds 已提交
225 226

bad_inode:
227 228
	iget_failed(inode);
	return ERR_PTR(-EIO);
L
Linus Torvalds 已提交
229 230
}

231
static int __sysv_write_inode(struct inode *inode, int wait)
L
Linus Torvalds 已提交
232 233 234 235 236 237 238
{
	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;
239
	int err = 0;
L
Linus Torvalds 已提交
240 241 242 243 244

	ino = inode->i_ino;
	if (!ino || ino > sbi->s_ninodes) {
		printk("Bad inode number on dev %s: %d is out of range\n",
		       inode->i_sb->s_id, ino);
245
		return -EIO;
L
Linus Torvalds 已提交
246 247 248 249
	}
	raw_inode = sysv_raw_inode(sb, ino, &bh);
	if (!raw_inode) {
		printk("unable to read i-node block\n");
250
		return -EIO;
L
Linus Torvalds 已提交
251 252 253
	}

	raw_inode->i_mode = cpu_to_fs16(sbi, inode->i_mode);
254 255
	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)));
L
Linus Torvalds 已提交
256 257 258 259 260 261 262 263 264 265 266 267 268
	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);
269 270 271 272 273 274 275 276
	if (wait) {
                sync_dirty_buffer(bh);
                if (buffer_req(bh) && !buffer_uptodate(bh)) {
                        printk ("IO error syncing sysv inode [%s:%08x]\n",
                                sb->s_id, ino);
                        err = -EIO;
                }
        }
L
Linus Torvalds 已提交
277 278 279 280
	brelse(bh);
	return 0;
}

281 282 283 284 285
int sysv_write_inode(struct inode *inode, struct writeback_control *wbc)
{
	return __sysv_write_inode(inode, wbc->sync_mode == WB_SYNC_ALL);
}

286
int sysv_sync_inode(struct inode *inode)
L
Linus Torvalds 已提交
287
{
288
	return __sysv_write_inode(inode, 1);
L
Linus Torvalds 已提交
289 290
}

A
Al Viro 已提交
291
static void sysv_evict_inode(struct inode *inode)
L
Linus Torvalds 已提交
292
{
293
	truncate_inode_pages_final(&inode->i_data);
A
Al Viro 已提交
294 295 296 297 298
	if (!inode->i_nlink) {
		inode->i_size = 0;
		sysv_truncate(inode);
	}
	invalidate_inode_buffers(inode);
299
	clear_inode(inode);
A
Al Viro 已提交
300 301
	if (!inode->i_nlink)
		sysv_free_inode(inode);
L
Linus Torvalds 已提交
302 303
}

304
static struct kmem_cache *sysv_inode_cachep;
L
Linus Torvalds 已提交
305 306 307 308 309

static struct inode *sysv_alloc_inode(struct super_block *sb)
{
	struct sysv_inode_info *si;

310
	si = kmem_cache_alloc(sysv_inode_cachep, GFP_KERNEL);
L
Linus Torvalds 已提交
311 312 313 314 315
	if (!si)
		return NULL;
	return &si->vfs_inode;
}

N
Nick Piggin 已提交
316
static void sysv_i_callback(struct rcu_head *head)
L
Linus Torvalds 已提交
317
{
N
Nick Piggin 已提交
318
	struct inode *inode = container_of(head, struct inode, i_rcu);
L
Linus Torvalds 已提交
319 320 321
	kmem_cache_free(sysv_inode_cachep, SYSV_I(inode));
}

N
Nick Piggin 已提交
322 323 324 325 326
static void sysv_destroy_inode(struct inode *inode)
{
	call_rcu(&inode->i_rcu, sysv_i_callback);
}

327
static void init_once(void *p)
L
Linus Torvalds 已提交
328 329 330
{
	struct sysv_inode_info *si = (struct sysv_inode_info *)p;

C
Christoph Lameter 已提交
331
	inode_init_once(&si->vfs_inode);
L
Linus Torvalds 已提交
332 333
}

334
const struct super_operations sysv_sops = {
L
Linus Torvalds 已提交
335 336 337
	.alloc_inode	= sysv_alloc_inode,
	.destroy_inode	= sysv_destroy_inode,
	.write_inode	= sysv_write_inode,
A
Al Viro 已提交
338
	.evict_inode	= sysv_evict_inode,
L
Linus Torvalds 已提交
339
	.put_super	= sysv_put_super,
C
Christoph Hellwig 已提交
340
	.sync_fs	= sysv_sync_fs,
L
Linus Torvalds 已提交
341 342 343 344 345 346 347 348
	.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,
349
			SLAB_RECLAIM_ACCOUNT|SLAB_MEM_SPREAD,
350
			init_once);
L
Linus Torvalds 已提交
351 352 353 354 355 356 357
	if (!sysv_inode_cachep)
		return -ENOMEM;
	return 0;
}

void sysv_destroy_icache(void)
{
358 359 360 361 362
	/*
	 * Make sure all delayed rcu free inodes are flushed before we
	 * destroy cache.
	 */
	rcu_barrier();
L
Linus Torvalds 已提交
363 364
	kmem_cache_destroy(sysv_inode_cachep);
}