1/*
2 *  linux/fs/sysv/ialloc.c
3 *
4 *  minix/bitmap.c
5 *  Copyright (C) 1991, 1992  Linus Torvalds
6 *
7 *  ext/freelists.c
8 *  Copyright (C) 1992  Remy Card (card@masi.ibp.fr)
9 *
10 *  xenix/alloc.c
11 *  Copyright (C) 1992  Doug Evans
12 *
13 *  coh/alloc.c
14 *  Copyright (C) 1993  Pascal Haible, Bruno Haible
15 *
16 *  sysv/ialloc.c
17 *  Copyright (C) 1993  Bruno Haible
18 *
19 *  This file contains code for allocating/freeing inodes.
20 */
21
22#include <linux/kernel.h>
23#include <linux/fs.h>
24#include <linux/sysv_fs.h>
25#include <linux/stddef.h>
26#include <linux/stat.h>
27#include <linux/string.h>
28#include <linux/locks.h>
29
30/* We don't trust the value of
31   sb->sv_sbd2->s_tinode = *sb->sv_sb_total_free_inodes
32   but we nevertheless keep it up to date. */
33
34/* An inode on disk is considered free if both i_mode == 0 and i_nlink == 0. */
35
36/* return &sb->sv_sb_fic_inodes[i] = &sbd->s_inode[i]; */
37static inline sysv_ino_t *
38sv_sb_fic_inode(struct super_block * sb, unsigned int i)
39{
40	if (sb->sv_bh1 == sb->sv_bh2)
41		return &sb->sv_sb_fic_inodes[i];
42	else {
43		/* 512 byte Xenix FS */
44		unsigned int offset = offsetof(struct xenix_super_block, s_inode[i]);
45		if (offset < 512)
46			return (sysv_ino_t*)(sb->sv_sbd1 + offset);
47		else
48			return (sysv_ino_t*)(sb->sv_sbd2 + offset);
49	}
50}
51
52struct sysv_inode *
53sysv_raw_inode(struct super_block *sb, unsigned ino, struct buffer_head **bh)
54{
55	struct sysv_inode *res;
56	int block = sb->sv_firstinodezone + sb->sv_block_base;
57	block += (ino-1) >> sb->sv_inodes_per_block_bits;
58	*bh = sb_bread(sb, block);
59	if (!*bh)
60		return NULL;
61	res = (struct sysv_inode *) (*bh)->b_data;
62	return res + ((ino-1) & sb->sv_inodes_per_block_1);
63}
64
65static int refill_free_cache(struct super_block *sb)
66{
67	struct buffer_head * bh;
68	struct sysv_inode * raw_inode;
69	int i = 0, ino;
70
71	ino = SYSV_ROOT_INO+1;
72	raw_inode = sysv_raw_inode(sb, ino, &bh);
73	if (!raw_inode)
74		goto out;
75	while (ino <= sb->sv_ninodes) {
76		if (raw_inode->i_mode == 0 && raw_inode->i_nlink == 0) {
77			*sv_sb_fic_inode(sb,i++) = cpu_to_fs16(sb, ino);
78			if (i == sb->sv_fic_size)
79				break;
80		}
81		if ((ino++ & sb->sv_inodes_per_block_1) == 0) {
82			brelse(bh);
83			raw_inode = sysv_raw_inode(sb, ino, &bh);
84			if (!raw_inode)
85				goto out;
86		} else
87			raw_inode++;
88	}
89	brelse(bh);
90out:
91	return i;
92}
93
94void sysv_free_inode(struct inode * inode)
95{
96	struct super_block * sb;
97	unsigned int ino;
98	struct buffer_head * bh;
99	struct sysv_inode * raw_inode;
100	unsigned count;
101
102	sb = inode->i_sb;
103	ino = inode->i_ino;
104	if (ino <= SYSV_ROOT_INO || ino > sb->sv_ninodes) {
105		printk("sysv_free_inode: inode 0,1,2 or nonexistent inode\n");
106		return;
107	}
108	raw_inode = sysv_raw_inode(sb, ino, &bh);
109	clear_inode(inode);
110	if (!raw_inode) {
111		printk("sysv_free_inode: unable to read inode block on device "
112		       "%s\n", bdevname(inode->i_dev));
113		return;
114	}
115	lock_super(sb);
116	count = fs16_to_cpu(sb, *sb->sv_sb_fic_count);
117	if (count < sb->sv_fic_size) {
118		*sv_sb_fic_inode(sb,count++) = cpu_to_fs16(sb, ino);
119		*sb->sv_sb_fic_count = cpu_to_fs16(sb, count);
120	}
121	fs16_add(sb, sb->sv_sb_total_free_inodes, 1);
122	dirty_sb(sb);
123	memset(raw_inode, 0, sizeof(struct sysv_inode));
124	mark_buffer_dirty(bh);
125	unlock_super(sb);
126	brelse(bh);
127}
128
129struct inode * sysv_new_inode(const struct inode * dir, mode_t mode)
130{
131	struct inode * inode;
132	struct super_block * sb;
133	u16 ino;
134	unsigned count;
135
136	sb = dir->i_sb;
137	inode = new_inode(sb);
138	if (!inode)
139		return ERR_PTR(-ENOMEM);
140
141	lock_super(sb);
142	count = fs16_to_cpu(sb, *sb->sv_sb_fic_count);
143	if (count == 0 || (*sv_sb_fic_inode(sb,count-1) == 0)) {
144		count = refill_free_cache(sb);
145		if (count == 0) {
146			iput(inode);
147			unlock_super(sb);
148			return ERR_PTR(-ENOSPC);
149		}
150	}
151	/* Now count > 0. */
152	ino = *sv_sb_fic_inode(sb,--count);
153	*sb->sv_sb_fic_count = cpu_to_fs16(sb, count);
154	fs16_add(sb, sb->sv_sb_total_free_inodes, -1);
155	dirty_sb(sb);
156
157	if (dir->i_mode & S_ISGID) {
158		inode->i_gid = dir->i_gid;
159		if (S_ISDIR(mode))
160			mode |= S_ISGID;
161	} else
162		inode->i_gid = current->fsgid;
163
164	inode->i_uid = current->fsuid;
165	inode->i_ino = fs16_to_cpu(sb, ino);
166	inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME;
167	inode->i_blocks = inode->i_blksize = 0;
168	inode->u.sysv_i.i_dir_start_lookup = 0;
169	insert_inode_hash(inode);
170	mark_inode_dirty(inode);
171
172	inode->i_mode = mode;		/* for sysv_write_inode() */
173	sysv_write_inode(inode, 0);	/* ensure inode not allocated again */
174	mark_inode_dirty(inode);	/* cleared by sysv_write_inode() */
175	/* That's it. */
176	unlock_super(sb);
177	return inode;
178}
179
180unsigned long sysv_count_free_inodes(struct super_block * sb)
181{
182	struct buffer_head * bh;
183	struct sysv_inode * raw_inode;
184	int ino, count, sb_count;
185
186	lock_super(sb);
187
188	sb_count = fs16_to_cpu(sb, *sb->sv_sb_total_free_inodes);
189
190	if (0)
191		goto trust_sb;
192
193	/* this causes a lot of disk traffic ... */
194	count = 0;
195	ino = SYSV_ROOT_INO+1;
196	raw_inode = sysv_raw_inode(sb, ino, &bh);
197	if (!raw_inode)
198		goto Eio;
199	while (ino <= sb->sv_ninodes) {
200		if (raw_inode->i_mode == 0 && raw_inode->i_nlink == 0)
201			count++;
202		if ((ino++ & sb->sv_inodes_per_block_1) == 0) {
203			brelse(bh);
204			raw_inode = sysv_raw_inode(sb, ino, &bh);
205			if (!raw_inode)
206				goto Eio;
207		} else
208			raw_inode++;
209	}
210	brelse(bh);
211	if (count != sb_count)
212		goto Einval;
213out:
214	unlock_super(sb);
215	return count;
216
217Einval:
218	printk("sysv_count_free_inodes: "
219		"free inode count was %d, correcting to %d\n",
220		sb_count, count);
221	if (!(sb->s_flags & MS_RDONLY)) {
222		*sb->sv_sb_total_free_inodes = cpu_to_fs16(sb, count);
223		dirty_sb(sb);
224	}
225	goto out;
226
227Eio:
228	printk("sysv_count_free_inodes: unable to read inode table\n");
229trust_sb:
230	count = sb_count;
231	goto out;
232}
233