Blame view

fs/affs/inode.c 10.6 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
  /*
   *  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...
13
  #include <linux/sched.h>
5b825c3af   Ingo Molnar   sched/headers: Pr...
14
  #include <linux/cred.h>
5a0e3ad6a   Tejun Heo   include cleanup: ...
15
  #include <linux/gfp.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
16
  #include "affs.h"
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
  	struct affs_sb_info	*sbi = AFFS_SB(sb);
  	struct buffer_head	*bh;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
21
  	struct affs_tail	*tail;
210f85596   David Howells   iget: stop AFFS f...
22
  	struct inode		*inode;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
23
24
25
26
  	u32			 block;
  	u32			 size;
  	u32			 prot;
  	u16			 id;
210f85596   David Howells   iget: stop AFFS f...
27
28
29
30
31
  	inode = iget_locked(sb, ino);
  	if (!inode)
  		return ERR_PTR(-ENOMEM);
  	if (!(inode->i_state & I_NEW))
  		return inode;
9606d9aa8   Fabian Frederick   fs/affs: pr_debug...
32
33
  	pr_debug("affs_iget(%lu)
  ", inode->i_ino);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
34
35
36
37
38
39
40
41
42
43
44
45
46
  
  	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;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
47
48
49
50
  	tail = AFFS_TAIL(sb, bh);
  	prot = be32_to_cpu(tail->protect);
  
  	inode->i_size = 0;
bfe868486   Miklos Szeredi   filesystems: add ...
51
  	set_nlink(inode, 1);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
52
53
54
55
  	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...
56
  	atomic_set(&AFFS_I(inode)->i_opencnt, 0);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
57
58
59
60
61
62
63
64
65
66
  	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;
79bda4d51   Fabian Frederick   fs/affs: use affs...
67
  	if (affs_test_opt(sbi->s_flags, SF_SETMODE))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
68
69
  		inode->i_mode = sbi->s_mode;
  	else
c16182085   Fabian Frederick   fs/affs: add pref...
70
  		inode->i_mode = affs_prot_to_mode(prot);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
71
72
  
  	id = be16_to_cpu(tail->uid);
79bda4d51   Fabian Frederick   fs/affs: use affs...
73
  	if (id == 0 || affs_test_opt(sbi->s_flags, SF_SETUID))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
74
  		inode->i_uid = sbi->s_uid;
79bda4d51   Fabian Frederick   fs/affs: use affs...
75
  	else if (id == 0xFFFF && affs_test_opt(sbi->s_flags, SF_MUFS))
8fed10be0   Eric W. Biederman   userns: Convert a...
76
  		i_uid_write(inode, 0);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
77
  	else
8fed10be0   Eric W. Biederman   userns: Convert a...
78
  		i_uid_write(inode, id);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
79
80
  
  	id = be16_to_cpu(tail->gid);
79bda4d51   Fabian Frederick   fs/affs: use affs...
81
  	if (id == 0 || affs_test_opt(sbi->s_flags, SF_SETGID))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
82
  		inode->i_gid = sbi->s_gid;
79bda4d51   Fabian Frederick   fs/affs: use affs...
83
  	else if (id == 0xFFFF && affs_test_opt(sbi->s_flags, SF_MUFS))
8fed10be0   Eric W. Biederman   userns: Convert a...
84
  		i_gid_write(inode, 0);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
85
  	else
8fed10be0   Eric W. Biederman   userns: Convert a...
86
  		i_gid_write(inode, id);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
87
88
89
90
91
  
  	switch (be32_to_cpu(tail->stype)) {
  	case ST_ROOT:
  		inode->i_uid = sbi->s_uid;
  		inode->i_gid = sbi->s_gid;
df561f668   Gustavo A. R. Silva   treewide: Use fal...
92
  		fallthrough;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
93
94
  	case ST_USERDIR:
  		if (be32_to_cpu(tail->stype) == ST_USERDIR ||
79bda4d51   Fabian Frederick   fs/affs: use affs...
95
  		    affs_test_opt(sbi->s_flags, SF_SETMODE)) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
96
97
98
99
100
101
102
103
104
  			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
105
106
107
108
109
110
111
112
113
114
115
  		/* 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...
116
  		/* ... and leave ->i_op and ->i_fop pointing to empty */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
  		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 ...
133
  			set_nlink(inode, 2);
79bda4d51   Fabian Frederick   fs/affs: use affs...
134
  		inode->i_mapping->a_ops = affs_test_opt(sbi->s_flags, SF_OFS) ?
a0016ff28   Fabian Frederick   fs/affs: use AFFS...
135
  					  &affs_aops_ofs : &affs_aops;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
136
137
138
139
  		inode->i_op = &affs_file_inode_operations;
  		inode->i_fop = &affs_file_operations;
  		break;
  	case ST_SOFTLINK:
f1bf90724   Fabian Frederick   fs/affs: bugfix: ...
140
  		inode->i_size = strlen((char *)AFFS_HEAD(bh)->table);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
141
  		inode->i_mode |= S_IFLNK;
21fc61c73   Al Viro   don't put symlink...
142
  		inode_nohighmem(inode);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
143
144
145
146
147
148
  		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
487b25bc4   Deepa Dinamani   fs: affs: Initial...
149
  		       = (be32_to_cpu(tail->change.days) * 86400LL +
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
150
151
  		         be32_to_cpu(tail->change.mins) * 60 +
  			 be32_to_cpu(tail->change.ticks) / 50 +
487b25bc4   Deepa Dinamani   fs: affs: Initial...
152
  			 AFFS_EPOCH_DELTA) +
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
153
154
155
  			 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...
156
157
  	unlock_new_inode(inode);
  	return inode;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
158
159
  
  bad_inode:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
160
  	affs_brelse(bh);
210f85596   David Howells   iget: stop AFFS f...
161
162
  	iget_failed(inode);
  	return ERR_PTR(-EIO);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
163
164
165
  }
  
  int
a9185b41a   Christoph Hellwig   pass writeback_co...
166
  affs_write_inode(struct inode *inode, struct writeback_control *wbc)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
167
168
169
170
171
172
  {
  	struct super_block	*sb = inode->i_sb;
  	struct buffer_head	*bh;
  	struct affs_tail	*tail;
  	uid_t			 uid;
  	gid_t			 gid;
9606d9aa8   Fabian Frederick   fs/affs: pr_debug...
173
174
  	pr_debug("write_inode(%lu)
  ", inode->i_ino);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
175
176
177
178
179
180
181
182
183
184
185
  
  	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)) {
c16182085   Fabian Frederick   fs/affs: add pref...
186
187
  		affs_secs_to_datestamp(inode->i_mtime.tv_sec,
  				       &AFFS_ROOT_TAIL(sb, bh)->root_change);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
188
189
190
  	} else {
  		tail->protect = cpu_to_be32(AFFS_I(inode)->i_protect);
  		tail->size = cpu_to_be32(inode->i_size);
c16182085   Fabian Frederick   fs/affs: add pref...
191
  		affs_secs_to_datestamp(inode->i_mtime.tv_sec, &tail->change);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
192
  		if (!(inode->i_ino == AFFS_SB(sb)->s_root_block)) {
8fed10be0   Eric W. Biederman   userns: Convert a...
193
194
  			uid = i_uid_read(inode);
  			gid = i_gid_read(inode);
79bda4d51   Fabian Frederick   fs/affs: use affs...
195
  			if (affs_test_opt(AFFS_SB(sb)->s_flags, SF_MUFS)) {
8fed10be0   Eric W. Biederman   userns: Convert a...
196
197
198
199
  				if (uid == 0 || uid == 0xFFFF)
  					uid = uid ^ ~0;
  				if (gid == 0 || gid == 0xFFFF)
  					gid = gid ^ ~0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
200
  			}
79bda4d51   Fabian Frederick   fs/affs: use affs...
201
  			if (!affs_test_opt(AFFS_SB(sb)->s_flags, SF_SETUID))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
202
  				tail->uid = cpu_to_be16(uid);
79bda4d51   Fabian Frederick   fs/affs: use affs...
203
  			if (!affs_test_opt(AFFS_SB(sb)->s_flags, SF_SETGID))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
204
205
206
207
208
209
210
211
212
213
214
215
216
  				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)
  {
2b0143b5c   David Howells   VFS: normal files...
217
  	struct inode *inode = d_inode(dentry);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
218
  	int error;
9606d9aa8   Fabian Frederick   fs/affs: pr_debug...
219
220
  	pr_debug("notify_change(%lu,0x%x)
  ", inode->i_ino, attr->ia_valid);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
221

31051c85b   Jan Kara   fs: Give dentry t...
222
  	error = setattr_prepare(dentry, attr);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
223
224
  	if (error)
  		goto out;
a0016ff28   Fabian Frederick   fs/affs: use AFFS...
225
  	if (((attr->ia_valid & ATTR_UID) &&
79bda4d51   Fabian Frederick   fs/affs: use affs...
226
  	      affs_test_opt(AFFS_SB(inode->i_sb)->s_flags, SF_SETUID)) ||
a0016ff28   Fabian Frederick   fs/affs: use AFFS...
227
  	    ((attr->ia_valid & ATTR_GID) &&
79bda4d51   Fabian Frederick   fs/affs: use affs...
228
  	      affs_test_opt(AFFS_SB(inode->i_sb)->s_flags, SF_SETGID)) ||
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
229
  	    ((attr->ia_valid & ATTR_MODE) &&
a0016ff28   Fabian Frederick   fs/affs: use AFFS...
230
231
  	     (AFFS_SB(inode->i_sb)->s_flags &
  	      (AFFS_MOUNT_SF_SETMODE | AFFS_MOUNT_SF_IMMUTABLE)))) {
79bda4d51   Fabian Frederick   fs/affs: use affs...
232
  		if (!affs_test_opt(AFFS_SB(inode->i_sb)->s_flags, SF_QUIET))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
233
234
235
  			error = -EPERM;
  		goto out;
  	}
1025774ce   Christoph Hellwig   remove inode_setattr
236
237
  	if ((attr->ia_valid & ATTR_SIZE) &&
  	    attr->ia_size != i_size_read(inode)) {
1dc1834f4   Marco Stornelli   affs: drop vmtrun...
238
  		error = inode_newsize_ok(inode, attr->ia_size);
1025774ce   Christoph Hellwig   remove inode_setattr
239
240
  		if (error)
  			return error;
1dc1834f4   Marco Stornelli   affs: drop vmtrun...
241
242
243
  
  		truncate_setsize(inode, attr->ia_size);
  		affs_truncate(inode);
1025774ce   Christoph Hellwig   remove inode_setattr
244
245
246
247
248
249
  	}
  
  	setattr_copy(inode, attr);
  	mark_inode_dirty(inode);
  
  	if (attr->ia_valid & ATTR_MODE)
c16182085   Fabian Frederick   fs/affs: add pref...
250
  		affs_mode_to_prot(inode);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
251
252
253
254
255
  out:
  	return error;
  }
  
  void
f053ddde7   Al Viro   switch affs to ->...
256
  affs_evict_inode(struct inode *inode)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
257
  {
dca3c3365   Roman Zippel   [PATCH] fix reser...
258
  	unsigned long cache_page;
9606d9aa8   Fabian Frederick   fs/affs: pr_debug...
259
260
261
  	pr_debug("evict_inode(ino=%lu, nlink=%u)
  ",
  		 inode->i_ino, inode->i_nlink);
91b0abe36   Johannes Weiner   mm + fs: store sh...
262
  	truncate_inode_pages_final(&inode->i_data);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
263

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

f053ddde7   Al Viro   switch affs to ->...
269
  	invalidate_inode_buffers(inode);
dbd5768f8   Jan Kara   vfs: Rename end_w...
270
  	clear_inode(inode);
dca3c3365   Roman Zippel   [PATCH] fix reser...
271
272
  	affs_free_prealloc(inode);
  	cache_page = (unsigned long)AFFS_I(inode)->i_lc;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
273
  	if (cache_page) {
9606d9aa8   Fabian Frederick   fs/affs: pr_debug...
274
275
  		pr_debug("freeing ext cache
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
276
277
278
279
280
281
282
  		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 ->...
283
284
285
  
  	if (!inode->i_nlink)
  		affs_free_block(inode->i_sb, inode->i_ino);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
  }
  
  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...
307
308
  	inode->i_uid     = current_fsuid();
  	inode->i_gid     = current_fsgid();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
309
  	inode->i_ino     = block;
bfe868486   Miklos Szeredi   filesystems: add ...
310
  	set_nlink(inode, 1);
02027d42c   Deepa Dinamani   fs: Replace CURRE...
311
  	inode->i_mtime   = inode->i_atime = inode->i_ctime = current_time(inode);
dca3c3365   Roman Zippel   [PATCH] fix reser...
312
  	atomic_set(&AFFS_I(inode)->i_opencnt, 0);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
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
  	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;
78f444f67   Fabian Frederick   fs/affs/inode.c: ...
349
  	struct buffer_head *bh;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
350
351
  	u32 block = 0;
  	int retval;
08fe100d9   Geert Uytterhoeven   fs/affs: fix cast...
352
353
354
  	pr_debug("%s(dir=%lu, inode=%lu, \"%pd\", type=%d)
  ", __func__,
  		 dir->i_ino, inode->i_ino, dentry, type);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
355
356
357
358
359
360
361
362
363
364
  
  	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
365
366
367
368
369
  		retval = -ENOSPC;
  		block = affs_alloc_block(dir, dir->i_ino);
  		if (!block)
  			goto err;
  		retval = -EIO;
dca3c3365   Roman Zippel   [PATCH] fix reser...
370
  		inode_bh = bh;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
  		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 ...
393
  		set_nlink(inode, 2);
7de9c6ee3   Al Viro   new helper: ihold()
394
  		ihold(inode);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
  	}
  	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;
  }