Blame view

fs/affs/inode.c 10.4 KB
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1
2
3
4
5
6
7
8
9
10
11
  /*
   *  linux/fs/affs/inode.c
   *
   *  (c) 1996  Hans-Joachim Widmaier - Rewritten
   *
   *  (C) 1993  Ray Burr - Modified for Amiga FFS filesystem.
   *
   *  (C) 1992  Eric Youngdale Modified for ISO9660 filesystem.
   *
   *  (C) 1991  Linus Torvalds - minix filesystem
   */
e8edc6e03   Alexey Dobriyan   Detach sched.h fr...
12
  #include <linux/sched.h>
5a0e3ad6a   Tejun Heo   include cleanup: ...
13
  #include <linux/gfp.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
14
  #include "affs.h"
754661f14   Arjan van de Ven   [PATCH] mark stru...
15
  extern const struct inode_operations affs_symlink_inode_operations;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
16
  extern struct timezone sys_tz;
210f85596   David Howells   iget: stop AFFS f...
17
  struct inode *affs_iget(struct super_block *sb, unsigned long ino)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
18
  {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
19
20
21
22
  	struct affs_sb_info	*sbi = AFFS_SB(sb);
  	struct buffer_head	*bh;
  	struct affs_head	*head;
  	struct affs_tail	*tail;
210f85596   David Howells   iget: stop AFFS f...
23
  	struct inode		*inode;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
24
25
26
27
  	u32			 block;
  	u32			 size;
  	u32			 prot;
  	u16			 id;
210f85596   David Howells   iget: stop AFFS f...
28
29
30
31
32
33
34
35
  	inode = iget_locked(sb, ino);
  	if (!inode)
  		return ERR_PTR(-ENOMEM);
  	if (!(inode->i_state & I_NEW))
  		return inode;
  
  	pr_debug("AFFS: affs_iget(%lu)
  ", inode->i_ino);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
  
  	block = inode->i_ino;
  	bh = affs_bread(sb, block);
  	if (!bh) {
  		affs_warning(sb, "read_inode", "Cannot read block %d", block);
  		goto bad_inode;
  	}
  	if (affs_checksum_block(sb, bh) || be32_to_cpu(AFFS_HEAD(bh)->ptype) != T_SHORT) {
  		affs_warning(sb,"read_inode",
  			   "Checksum or type (ptype=%d) error on inode %d",
  			   AFFS_HEAD(bh)->ptype, block);
  		goto bad_inode;
  	}
  
  	head = AFFS_HEAD(bh);
  	tail = AFFS_TAIL(sb, bh);
  	prot = be32_to_cpu(tail->protect);
  
  	inode->i_size = 0;
bfe868486   Miklos Szeredi   filesystems: add ...
55
  	set_nlink(inode, 1);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
56
57
58
59
  	inode->i_mode = 0;
  	AFFS_I(inode)->i_extcnt = 1;
  	AFFS_I(inode)->i_ext_last = ~1;
  	AFFS_I(inode)->i_protect = prot;
dca3c3365   Roman Zippel   [PATCH] fix reser...
60
  	atomic_set(&AFFS_I(inode)->i_opencnt, 0);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
  	AFFS_I(inode)->i_blkcnt = 0;
  	AFFS_I(inode)->i_lc = NULL;
  	AFFS_I(inode)->i_lc_size = 0;
  	AFFS_I(inode)->i_lc_shift = 0;
  	AFFS_I(inode)->i_lc_mask = 0;
  	AFFS_I(inode)->i_ac = NULL;
  	AFFS_I(inode)->i_ext_bh = NULL;
  	AFFS_I(inode)->mmu_private = 0;
  	AFFS_I(inode)->i_lastalloc = 0;
  	AFFS_I(inode)->i_pa_cnt = 0;
  
  	if (sbi->s_flags & SF_SETMODE)
  		inode->i_mode = sbi->s_mode;
  	else
  		inode->i_mode = prot_to_mode(prot);
  
  	id = be16_to_cpu(tail->uid);
  	if (id == 0 || sbi->s_flags & SF_SETUID)
  		inode->i_uid = sbi->s_uid;
  	else if (id == 0xFFFF && sbi->s_flags & SF_MUFS)
  		inode->i_uid = 0;
  	else
  		inode->i_uid = id;
  
  	id = be16_to_cpu(tail->gid);
  	if (id == 0 || sbi->s_flags & SF_SETGID)
  		inode->i_gid = sbi->s_gid;
  	else if (id == 0xFFFF && sbi->s_flags & SF_MUFS)
  		inode->i_gid = 0;
  	else
  		inode->i_gid = id;
  
  	switch (be32_to_cpu(tail->stype)) {
  	case ST_ROOT:
  		inode->i_uid = sbi->s_uid;
  		inode->i_gid = sbi->s_gid;
  		/* fall through */
  	case ST_USERDIR:
  		if (be32_to_cpu(tail->stype) == ST_USERDIR ||
  		    sbi->s_flags & SF_SETMODE) {
  			if (inode->i_mode & S_IRUSR)
  				inode->i_mode |= S_IXUSR;
  			if (inode->i_mode & S_IRGRP)
  				inode->i_mode |= S_IXGRP;
  			if (inode->i_mode & S_IROTH)
  				inode->i_mode |= S_IXOTH;
  			inode->i_mode |= S_IFDIR;
  		} else
  			inode->i_mode = S_IRUGO | S_IXUGO | S_IWUSR | S_IFDIR;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
110
111
112
113
114
115
116
117
118
119
120
  		/* Maybe it should be controlled by mount parameter? */
  		//inode->i_mode |= S_ISVTX;
  		inode->i_op = &affs_dir_inode_operations;
  		inode->i_fop = &affs_dir_operations;
  		break;
  	case ST_LINKDIR:
  #if 0
  		affs_warning(sb, "read_inode", "inode is LINKDIR");
  		goto bad_inode;
  #else
  		inode->i_mode |= S_IFDIR;
c765d4790   Al Viro   affs: do not zero...
121
  		/* ... and leave ->i_op and ->i_fop pointing to empty */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
  		break;
  #endif
  	case ST_LINKFILE:
  		affs_warning(sb, "read_inode", "inode is LINKFILE");
  		goto bad_inode;
  	case ST_FILE:
  		size = be32_to_cpu(tail->size);
  		inode->i_mode |= S_IFREG;
  		AFFS_I(inode)->mmu_private = inode->i_size = size;
  		if (inode->i_size) {
  			AFFS_I(inode)->i_blkcnt = (size - 1) /
  					       sbi->s_data_blksize + 1;
  			AFFS_I(inode)->i_extcnt = (AFFS_I(inode)->i_blkcnt - 1) /
  					       sbi->s_hashsize + 1;
  		}
  		if (tail->link_chain)
bfe868486   Miklos Szeredi   filesystems: add ...
138
  			set_nlink(inode, 2);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
  		inode->i_mapping->a_ops = (sbi->s_flags & SF_OFS) ? &affs_aops_ofs : &affs_aops;
  		inode->i_op = &affs_file_inode_operations;
  		inode->i_fop = &affs_file_operations;
  		break;
  	case ST_SOFTLINK:
  		inode->i_mode |= S_IFLNK;
  		inode->i_op = &affs_symlink_inode_operations;
  		inode->i_data.a_ops = &affs_symlink_aops;
  		break;
  	}
  
  	inode->i_mtime.tv_sec = inode->i_atime.tv_sec = inode->i_ctime.tv_sec
  		       = (be32_to_cpu(tail->change.days) * (24 * 60 * 60) +
  		         be32_to_cpu(tail->change.mins) * 60 +
  			 be32_to_cpu(tail->change.ticks) / 50 +
  			 ((8 * 365 + 2) * 24 * 60 * 60)) +
  			 sys_tz.tz_minuteswest * 60;
  	inode->i_mtime.tv_nsec = inode->i_ctime.tv_nsec = inode->i_atime.tv_nsec = 0;
  	affs_brelse(bh);
210f85596   David Howells   iget: stop AFFS f...
158
159
  	unlock_new_inode(inode);
  	return inode;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
160
161
  
  bad_inode:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
162
  	affs_brelse(bh);
210f85596   David Howells   iget: stop AFFS f...
163
164
  	iget_failed(inode);
  	return ERR_PTR(-EIO);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
165
166
167
  }
  
  int
a9185b41a   Christoph Hellwig   pass writeback_co...
168
  affs_write_inode(struct inode *inode, struct writeback_control *wbc)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
  {
  	struct super_block	*sb = inode->i_sb;
  	struct buffer_head	*bh;
  	struct affs_tail	*tail;
  	uid_t			 uid;
  	gid_t			 gid;
  
  	pr_debug("AFFS: write_inode(%lu)
  ",inode->i_ino);
  
  	if (!inode->i_nlink)
  		// possibly free block
  		return 0;
  	bh = affs_bread(sb, inode->i_ino);
  	if (!bh) {
  		affs_error(sb,"write_inode","Cannot read block %lu",inode->i_ino);
  		return -EIO;
  	}
  	tail = AFFS_TAIL(sb, bh);
  	if (tail->stype == cpu_to_be32(ST_ROOT)) {
  		secs_to_datestamp(inode->i_mtime.tv_sec,&AFFS_ROOT_TAIL(sb, bh)->root_change);
  	} else {
  		tail->protect = cpu_to_be32(AFFS_I(inode)->i_protect);
  		tail->size = cpu_to_be32(inode->i_size);
  		secs_to_datestamp(inode->i_mtime.tv_sec,&tail->change);
  		if (!(inode->i_ino == AFFS_SB(sb)->s_root_block)) {
  			uid = inode->i_uid;
  			gid = inode->i_gid;
  			if (AFFS_SB(sb)->s_flags & SF_MUFS) {
  				if (inode->i_uid == 0 || inode->i_uid == 0xFFFF)
  					uid = inode->i_uid ^ ~0;
  				if (inode->i_gid == 0 || inode->i_gid == 0xFFFF)
  					gid = inode->i_gid ^ ~0;
  			}
  			if (!(AFFS_SB(sb)->s_flags & SF_SETUID))
  				tail->uid = cpu_to_be16(uid);
  			if (!(AFFS_SB(sb)->s_flags & SF_SETGID))
  				tail->gid = cpu_to_be16(gid);
  		}
  	}
  	affs_fix_checksum(sb, bh);
  	mark_buffer_dirty_inode(bh, inode);
  	affs_brelse(bh);
  	affs_free_prealloc(inode);
  	return 0;
  }
  
  int
  affs_notify_change(struct dentry *dentry, struct iattr *attr)
  {
  	struct inode *inode = dentry->d_inode;
  	int error;
  
  	pr_debug("AFFS: notify_change(%lu,0x%x)
  ",inode->i_ino,attr->ia_valid);
  
  	error = inode_change_ok(inode,attr);
  	if (error)
  		goto out;
  
  	if (((attr->ia_valid & ATTR_UID) && (AFFS_SB(inode->i_sb)->s_flags & SF_SETUID)) ||
  	    ((attr->ia_valid & ATTR_GID) && (AFFS_SB(inode->i_sb)->s_flags & SF_SETGID)) ||
  	    ((attr->ia_valid & ATTR_MODE) &&
  	     (AFFS_SB(inode->i_sb)->s_flags & (SF_SETMODE | SF_IMMUTABLE)))) {
  		if (!(AFFS_SB(inode->i_sb)->s_flags & SF_QUIET))
  			error = -EPERM;
  		goto out;
  	}
1025774ce   Christoph Hellwig   remove inode_setattr
237
238
239
240
241
242
243
244
245
246
247
  	if ((attr->ia_valid & ATTR_SIZE) &&
  	    attr->ia_size != i_size_read(inode)) {
  		error = vmtruncate(inode, attr->ia_size);
  		if (error)
  			return error;
  	}
  
  	setattr_copy(inode, attr);
  	mark_inode_dirty(inode);
  
  	if (attr->ia_valid & ATTR_MODE)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
248
249
250
251
252
253
  		mode_to_prot(inode);
  out:
  	return error;
  }
  
  void
f053ddde7   Al Viro   switch affs to ->...
254
  affs_evict_inode(struct inode *inode)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
255
  {
dca3c3365   Roman Zippel   [PATCH] fix reser...
256
  	unsigned long cache_page;
f053ddde7   Al Viro   switch affs to ->...
257
258
259
  	pr_debug("AFFS: evict_inode(ino=%lu, nlink=%u)
  ", inode->i_ino, inode->i_nlink);
  	truncate_inode_pages(&inode->i_data, 0);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
260

f053ddde7   Al Viro   switch affs to ->...
261
262
263
264
  	if (!inode->i_nlink) {
  		inode->i_size = 0;
  		affs_truncate(inode);
  	}
dca3c3365   Roman Zippel   [PATCH] fix reser...
265

f053ddde7   Al Viro   switch affs to ->...
266
267
  	invalidate_inode_buffers(inode);
  	end_writeback(inode);
dca3c3365   Roman Zippel   [PATCH] fix reser...
268
269
  	affs_free_prealloc(inode);
  	cache_page = (unsigned long)AFFS_I(inode)->i_lc;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
270
271
272
273
274
275
276
277
278
279
  	if (cache_page) {
  		pr_debug("AFFS: freeing ext cache
  ");
  		AFFS_I(inode)->i_lc = NULL;
  		AFFS_I(inode)->i_ac = NULL;
  		free_page(cache_page);
  	}
  	affs_brelse(AFFS_I(inode)->i_ext_bh);
  	AFFS_I(inode)->i_ext_last = ~1;
  	AFFS_I(inode)->i_ext_bh = NULL;
f053ddde7   Al Viro   switch affs to ->...
280
281
282
  
  	if (!inode->i_nlink)
  		affs_free_block(inode->i_sb, inode->i_ino);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
  }
  
  struct inode *
  affs_new_inode(struct inode *dir)
  {
  	struct super_block	*sb = dir->i_sb;
  	struct inode		*inode;
  	u32			 block;
  	struct buffer_head	*bh;
  
  	if (!(inode = new_inode(sb)))
  		goto err_inode;
  
  	if (!(block = affs_alloc_block(dir, dir->i_ino)))
  		goto err_block;
  
  	bh = affs_getzeroblk(sb, block);
  	if (!bh)
  		goto err_bh;
  	mark_buffer_dirty_inode(bh, inode);
  	affs_brelse(bh);
215599815   David Howells   CRED: Wrap task c...
304
305
  	inode->i_uid     = current_fsuid();
  	inode->i_gid     = current_fsgid();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
306
  	inode->i_ino     = block;
bfe868486   Miklos Szeredi   filesystems: add ...
307
  	set_nlink(inode, 1);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
308
  	inode->i_mtime   = inode->i_atime = inode->i_ctime = CURRENT_TIME_SEC;
dca3c3365   Roman Zippel   [PATCH] fix reser...
309
  	atomic_set(&AFFS_I(inode)->i_opencnt, 0);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
  	AFFS_I(inode)->i_blkcnt = 0;
  	AFFS_I(inode)->i_lc = NULL;
  	AFFS_I(inode)->i_lc_size = 0;
  	AFFS_I(inode)->i_lc_shift = 0;
  	AFFS_I(inode)->i_lc_mask = 0;
  	AFFS_I(inode)->i_ac = NULL;
  	AFFS_I(inode)->i_ext_bh = NULL;
  	AFFS_I(inode)->mmu_private = 0;
  	AFFS_I(inode)->i_protect = 0;
  	AFFS_I(inode)->i_lastalloc = 0;
  	AFFS_I(inode)->i_pa_cnt = 0;
  	AFFS_I(inode)->i_extcnt = 1;
  	AFFS_I(inode)->i_ext_last = ~1;
  
  	insert_inode_hash(inode);
  
  	return inode;
  
  err_bh:
  	affs_free_block(sb, block);
  err_block:
  	iput(inode);
  err_inode:
  	return NULL;
  }
  
  /*
   * Add an entry to a directory. Create the header block
   * and insert it into the hash table.
   */
  
  int
  affs_add_entry(struct inode *dir, struct inode *inode, struct dentry *dentry, s32 type)
  {
  	struct super_block *sb = dir->i_sb;
  	struct buffer_head *inode_bh = NULL;
  	struct buffer_head *bh = NULL;
  	u32 block = 0;
  	int retval;
  
  	pr_debug("AFFS: add_entry(dir=%u, inode=%u, \"%*s\", type=%d)
  ", (u32)dir->i_ino,
  	         (u32)inode->i_ino, (int)dentry->d_name.len, dentry->d_name.name, type);
  
  	retval = -EIO;
  	bh = affs_bread(sb, inode->i_ino);
  	if (!bh)
  		goto done;
  
  	affs_lock_link(inode);
  	switch (type) {
  	case ST_LINKFILE:
  	case ST_LINKDIR:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
363
364
365
366
367
  		retval = -ENOSPC;
  		block = affs_alloc_block(dir, dir->i_ino);
  		if (!block)
  			goto err;
  		retval = -EIO;
dca3c3365   Roman Zippel   [PATCH] fix reser...
368
  		inode_bh = bh;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
  		bh = affs_getzeroblk(sb, block);
  		if (!bh)
  			goto err;
  		break;
  	default:
  		break;
  	}
  
  	AFFS_HEAD(bh)->ptype = cpu_to_be32(T_SHORT);
  	AFFS_HEAD(bh)->key = cpu_to_be32(bh->b_blocknr);
  	affs_copy_name(AFFS_TAIL(sb, bh)->name, dentry);
  	AFFS_TAIL(sb, bh)->stype = cpu_to_be32(type);
  	AFFS_TAIL(sb, bh)->parent = cpu_to_be32(dir->i_ino);
  
  	if (inode_bh) {
  		__be32 chain;
  	       	chain = AFFS_TAIL(sb, inode_bh)->link_chain;
  		AFFS_TAIL(sb, bh)->original = cpu_to_be32(inode->i_ino);
  		AFFS_TAIL(sb, bh)->link_chain = chain;
  		AFFS_TAIL(sb, inode_bh)->link_chain = cpu_to_be32(block);
  		affs_adjust_checksum(inode_bh, block - be32_to_cpu(chain));
  		mark_buffer_dirty_inode(inode_bh, inode);
bfe868486   Miklos Szeredi   filesystems: add ...
391
  		set_nlink(inode, 2);
7de9c6ee3   Al Viro   new helper: ihold()
392
  		ihold(inode);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
  	}
  	affs_fix_checksum(sb, bh);
  	mark_buffer_dirty_inode(bh, inode);
  	dentry->d_fsdata = (void *)(long)bh->b_blocknr;
  
  	affs_lock_dir(dir);
  	retval = affs_insert_hash(dir, bh);
  	mark_buffer_dirty_inode(bh, inode);
  	affs_unlock_dir(dir);
  	affs_unlock_link(inode);
  
  	d_instantiate(dentry, inode);
  done:
  	affs_brelse(inode_bh);
  	affs_brelse(bh);
  	return retval;
  err:
  	if (block)
  		affs_free_block(sb, block);
  	affs_unlock_link(inode);
  	goto done;
  }