blob: 0c06f92368f2d25716887bb5646d7d2dfd584f37 [file] [log] [blame]
David Teiglandb3b94fa2006-01-16 16:50:04 +00001/*
2 * Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved.
Steven Whitehouse3a8a9a12006-05-18 15:09:15 -04003 * Copyright (C) 2004-2006 Red Hat, Inc. All rights reserved.
David Teiglandb3b94fa2006-01-16 16:50:04 +00004 *
5 * This copyrighted material is made available to anyone wishing to use,
6 * modify, copy, or redistribute it subject to the terms and conditions
7 * of the GNU General Public License v.2.
8 */
9
10#include <linux/sched.h>
11#include <linux/slab.h>
12#include <linux/spinlock.h>
13#include <linux/completion.h>
14#include <linux/buffer_head.h>
15#include <linux/namei.h>
16#include <linux/utsname.h>
17#include <linux/mm.h>
18#include <linux/xattr.h>
19#include <linux/posix_acl.h>
Steven Whitehouse5c676f62006-02-27 17:23:27 -050020#include <linux/gfs2_ondisk.h>
Steven Whitehouse71b86f52006-03-28 14:14:04 -050021#include <linux/crc32.h>
David Teiglandb3b94fa2006-01-16 16:50:04 +000022#include <asm/uaccess.h>
23
24#include "gfs2.h"
Steven Whitehouse5c676f62006-02-27 17:23:27 -050025#include "lm_interface.h"
26#include "incore.h"
David Teiglandb3b94fa2006-01-16 16:50:04 +000027#include "acl.h"
28#include "bmap.h"
29#include "dir.h"
30#include "eaops.h"
31#include "eattr.h"
32#include "glock.h"
33#include "inode.h"
34#include "meta_io.h"
35#include "ops_dentry.h"
36#include "ops_inode.h"
37#include "page.h"
38#include "quota.h"
39#include "rgrp.h"
40#include "trans.h"
41#include "unlinked.h"
Steven Whitehouse5c676f62006-02-27 17:23:27 -050042#include "util.h"
David Teiglandb3b94fa2006-01-16 16:50:04 +000043
44/**
45 * gfs2_create - Create a file
46 * @dir: The directory in which to create the file
47 * @dentry: The dentry of the new file
48 * @mode: The mode of the new file
49 *
50 * Returns: errno
51 */
52
53static int gfs2_create(struct inode *dir, struct dentry *dentry,
54 int mode, struct nameidata *nd)
55{
Steven Whitehouse5c676f62006-02-27 17:23:27 -050056 struct gfs2_inode *dip = dir->u.generic_ip;
David Teiglandb3b94fa2006-01-16 16:50:04 +000057 struct gfs2_sbd *sdp = dip->i_sbd;
58 struct gfs2_holder ghs[2];
59 struct inode *inode;
60 int new = 1;
David Teiglandb3b94fa2006-01-16 16:50:04 +000061
David Teiglandb3b94fa2006-01-16 16:50:04 +000062 gfs2_holder_init(dip->i_gl, 0, 0, ghs);
63
64 for (;;) {
Steven Whitehouse7359a192006-02-13 12:27:43 +000065 inode = gfs2_createi(ghs, &dentry->d_name, S_IFREG | mode);
66 if (!IS_ERR(inode)) {
David Teiglandb3b94fa2006-01-16 16:50:04 +000067 gfs2_trans_end(sdp);
68 if (dip->i_alloc.al_rgd)
69 gfs2_inplace_release(dip);
70 gfs2_quota_unlock(dip);
71 gfs2_alloc_put(dip);
72 gfs2_glock_dq_uninit_m(2, ghs);
73 break;
Steven Whitehouse7359a192006-02-13 12:27:43 +000074 } else if (PTR_ERR(inode) != -EEXIST ||
David Teiglandb3b94fa2006-01-16 16:50:04 +000075 (nd->intent.open.flags & O_EXCL)) {
76 gfs2_holder_uninit(ghs);
Steven Whitehouse7359a192006-02-13 12:27:43 +000077 return PTR_ERR(inode);
David Teiglandb3b94fa2006-01-16 16:50:04 +000078 }
79
Steven Whitehousec7526662006-03-20 12:30:04 -050080 inode = gfs2_lookupi(dir, &dentry->d_name, 0, nd);
81 if (inode) {
82 if (!IS_ERR(inode)) {
83 new = 0;
84 gfs2_holder_uninit(ghs);
85 break;
86 } else {
87 gfs2_holder_uninit(ghs);
88 return PTR_ERR(inode);
89 }
David Teiglandb3b94fa2006-01-16 16:50:04 +000090 }
91 }
92
David Teiglandb3b94fa2006-01-16 16:50:04 +000093 d_instantiate(dentry, inode);
94 if (new)
95 mark_inode_dirty(inode);
96
97 return 0;
98}
99
100/**
101 * gfs2_lookup - Look up a filename in a directory and return its inode
102 * @dir: The directory inode
103 * @dentry: The dentry of the new inode
104 * @nd: passed from Linux VFS, ignored by us
105 *
106 * Called by the VFS layer. Lock dir and call gfs2_lookupi()
107 *
108 * Returns: errno
109 */
110
111static struct dentry *gfs2_lookup(struct inode *dir, struct dentry *dentry,
112 struct nameidata *nd)
113{
David Teiglandb3b94fa2006-01-16 16:50:04 +0000114 struct inode *inode = NULL;
David Teiglandb3b94fa2006-01-16 16:50:04 +0000115
Steven Whitehousec7526662006-03-20 12:30:04 -0500116 dentry->d_op = &gfs2_dops;
David Teiglandb3b94fa2006-01-16 16:50:04 +0000117
Steven Whitehousec7526662006-03-20 12:30:04 -0500118 inode = gfs2_lookupi(dir, &dentry->d_name, 0, nd);
119 if (inode && IS_ERR(inode))
120 return ERR_PTR(PTR_ERR(inode));
David Teiglandb3b94fa2006-01-16 16:50:04 +0000121
122 if (inode)
123 return d_splice_alias(inode, dentry);
124 d_add(dentry, inode);
125
126 return NULL;
127}
128
129/**
130 * gfs2_link - Link to a file
131 * @old_dentry: The inode to link
132 * @dir: Add link to this directory
133 * @dentry: The name of the link
134 *
135 * Link the inode in "old_dentry" into the directory "dir" with the
136 * name in "dentry".
137 *
138 * Returns: errno
139 */
140
141static int gfs2_link(struct dentry *old_dentry, struct inode *dir,
142 struct dentry *dentry)
143{
Steven Whitehouse5c676f62006-02-27 17:23:27 -0500144 struct gfs2_inode *dip = dir->u.generic_ip;
David Teiglandb3b94fa2006-01-16 16:50:04 +0000145 struct gfs2_sbd *sdp = dip->i_sbd;
146 struct inode *inode = old_dentry->d_inode;
Steven Whitehouse5c676f62006-02-27 17:23:27 -0500147 struct gfs2_inode *ip = inode->u.generic_ip;
David Teiglandb3b94fa2006-01-16 16:50:04 +0000148 struct gfs2_holder ghs[2];
149 int alloc_required;
150 int error;
151
David Teiglandb3b94fa2006-01-16 16:50:04 +0000152 if (S_ISDIR(ip->i_di.di_mode))
153 return -EPERM;
154
155 gfs2_holder_init(dip->i_gl, LM_ST_EXCLUSIVE, 0, ghs);
156 gfs2_holder_init(ip->i_gl, LM_ST_EXCLUSIVE, 0, ghs + 1);
157
158 error = gfs2_glock_nq_m(2, ghs);
159 if (error)
160 goto out;
161
162 error = gfs2_repermission(dir, MAY_WRITE | MAY_EXEC, NULL);
163 if (error)
164 goto out_gunlock;
165
Steven Whitehousec7526662006-03-20 12:30:04 -0500166 error = gfs2_dir_search(dir, &dentry->d_name, NULL, NULL);
David Teiglandb3b94fa2006-01-16 16:50:04 +0000167 switch (error) {
168 case -ENOENT:
169 break;
170 case 0:
171 error = -EEXIST;
172 default:
173 goto out_gunlock;
174 }
175
176 error = -EINVAL;
177 if (!dip->i_di.di_nlink)
178 goto out_gunlock;
179 error = -EFBIG;
180 if (dip->i_di.di_entries == (uint32_t)-1)
181 goto out_gunlock;
182 error = -EPERM;
183 if (IS_IMMUTABLE(inode) || IS_APPEND(inode))
184 goto out_gunlock;
185 error = -EINVAL;
186 if (!ip->i_di.di_nlink)
187 goto out_gunlock;
188 error = -EMLINK;
189 if (ip->i_di.di_nlink == (uint32_t)-1)
190 goto out_gunlock;
191
Steven Whitehousec7526662006-03-20 12:30:04 -0500192 alloc_required = error = gfs2_diradd_alloc_required(dir, &dentry->d_name);
193 if (error < 0)
David Teiglandb3b94fa2006-01-16 16:50:04 +0000194 goto out_gunlock;
Steven Whitehousec7526662006-03-20 12:30:04 -0500195 error = 0;
David Teiglandb3b94fa2006-01-16 16:50:04 +0000196
197 if (alloc_required) {
198 struct gfs2_alloc *al = gfs2_alloc_get(dip);
199
200 error = gfs2_quota_lock(dip, NO_QUOTA_CHANGE, NO_QUOTA_CHANGE);
201 if (error)
202 goto out_alloc;
203
204 error = gfs2_quota_check(dip, dip->i_di.di_uid,
205 dip->i_di.di_gid);
206 if (error)
207 goto out_gunlock_q;
208
209 al->al_requested = sdp->sd_max_dirres;
210
211 error = gfs2_inplace_reserve(dip);
212 if (error)
213 goto out_gunlock_q;
214
Steven Whitehouse1b502592006-05-18 14:10:52 -0400215 error = gfs2_trans_begin(sdp, sdp->sd_max_dirres +
David Teiglandb3b94fa2006-01-16 16:50:04 +0000216 al->al_rgd->rd_ri.ri_length +
217 2 * RES_DINODE + RES_STATFS +
218 RES_QUOTA, 0);
219 if (error)
220 goto out_ipres;
221 } else {
222 error = gfs2_trans_begin(sdp, 2 * RES_DINODE + RES_LEAF, 0);
223 if (error)
224 goto out_ipres;
225 }
226
Steven Whitehousec7526662006-03-20 12:30:04 -0500227 error = gfs2_dir_add(dir, &dentry->d_name, &ip->i_num,
David Teiglandb3b94fa2006-01-16 16:50:04 +0000228 IF2DT(ip->i_di.di_mode));
229 if (error)
230 goto out_end_trans;
231
232 error = gfs2_change_nlink(ip, +1);
233
234 out_end_trans:
235 gfs2_trans_end(sdp);
236
237 out_ipres:
238 if (alloc_required)
239 gfs2_inplace_release(dip);
240
241 out_gunlock_q:
242 if (alloc_required)
243 gfs2_quota_unlock(dip);
244
245 out_alloc:
246 if (alloc_required)
247 gfs2_alloc_put(dip);
248
249 out_gunlock:
250 gfs2_glock_dq_m(2, ghs);
251
252 out:
253 gfs2_holder_uninit(ghs);
254 gfs2_holder_uninit(ghs + 1);
255
256 if (!error) {
257 atomic_inc(&inode->i_count);
258 d_instantiate(dentry, inode);
259 mark_inode_dirty(inode);
260 }
261
262 return error;
263}
264
265/**
266 * gfs2_unlink - Unlink a file
267 * @dir: The inode of the directory containing the file to unlink
268 * @dentry: The file itself
269 *
270 * Unlink a file. Call gfs2_unlinki()
271 *
272 * Returns: errno
273 */
274
275static int gfs2_unlink(struct inode *dir, struct dentry *dentry)
276{
Steven Whitehouse5c676f62006-02-27 17:23:27 -0500277 struct gfs2_inode *dip = dir->u.generic_ip;
David Teiglandb3b94fa2006-01-16 16:50:04 +0000278 struct gfs2_sbd *sdp = dip->i_sbd;
Steven Whitehouse5c676f62006-02-27 17:23:27 -0500279 struct gfs2_inode *ip = dentry->d_inode->u.generic_ip;
David Teiglandb3b94fa2006-01-16 16:50:04 +0000280 struct gfs2_unlinked *ul;
281 struct gfs2_holder ghs[2];
282 int error;
283
David Teiglandb3b94fa2006-01-16 16:50:04 +0000284 error = gfs2_unlinked_get(sdp, &ul);
285 if (error)
286 return error;
287
288 gfs2_holder_init(dip->i_gl, LM_ST_EXCLUSIVE, 0, ghs);
289 gfs2_holder_init(ip->i_gl, LM_ST_EXCLUSIVE, 0, ghs + 1);
290
291 error = gfs2_glock_nq_m(2, ghs);
292 if (error)
293 goto out;
294
295 error = gfs2_unlink_ok(dip, &dentry->d_name, ip);
296 if (error)
297 goto out_gunlock;
298
299 error = gfs2_trans_begin(sdp, 2 * RES_DINODE + RES_LEAF +
300 RES_UNLINKED, 0);
301 if (error)
302 goto out_gunlock;
303
Steven Whitehouse1b502592006-05-18 14:10:52 -0400304 error = gfs2_unlinki(dip, &dentry->d_name, ip, ul);
David Teiglandb3b94fa2006-01-16 16:50:04 +0000305
306 gfs2_trans_end(sdp);
307
308 out_gunlock:
309 gfs2_glock_dq_m(2, ghs);
310
311 out:
312 gfs2_holder_uninit(ghs);
313 gfs2_holder_uninit(ghs + 1);
314
315 gfs2_unlinked_put(sdp, ul);
316
317 return error;
318}
319
320/**
321 * gfs2_symlink - Create a symlink
322 * @dir: The directory to create the symlink in
323 * @dentry: The dentry to put the symlink in
324 * @symname: The thing which the link points to
325 *
326 * Returns: errno
327 */
328
329static int gfs2_symlink(struct inode *dir, struct dentry *dentry,
330 const char *symname)
331{
Steven Whitehouse5c676f62006-02-27 17:23:27 -0500332 struct gfs2_inode *dip = dir->u.generic_ip, *ip;
David Teiglandb3b94fa2006-01-16 16:50:04 +0000333 struct gfs2_sbd *sdp = dip->i_sbd;
334 struct gfs2_holder ghs[2];
335 struct inode *inode;
336 struct buffer_head *dibh;
337 int size;
338 int error;
339
David Teiglandb3b94fa2006-01-16 16:50:04 +0000340 /* Must be stuffed with a null terminator for gfs2_follow_link() */
341 size = strlen(symname);
342 if (size > sdp->sd_sb.sb_bsize - sizeof(struct gfs2_dinode) - 1)
343 return -ENAMETOOLONG;
344
345 gfs2_holder_init(dip->i_gl, 0, 0, ghs);
346
Steven Whitehouse7359a192006-02-13 12:27:43 +0000347 inode = gfs2_createi(ghs, &dentry->d_name, S_IFLNK | S_IRWXUGO);
348 if (IS_ERR(inode)) {
David Teiglandb3b94fa2006-01-16 16:50:04 +0000349 gfs2_holder_uninit(ghs);
Steven Whitehouse7359a192006-02-13 12:27:43 +0000350 return PTR_ERR(inode);
David Teiglandb3b94fa2006-01-16 16:50:04 +0000351 }
352
Steven Whitehouse5c676f62006-02-27 17:23:27 -0500353 ip = ghs[1].gh_gl->gl_object;
David Teiglandb3b94fa2006-01-16 16:50:04 +0000354
355 ip->i_di.di_size = size;
356
357 error = gfs2_meta_inode_buffer(ip, &dibh);
358
359 if (!gfs2_assert_withdraw(sdp, !error)) {
360 gfs2_dinode_out(&ip->i_di, dibh->b_data);
361 memcpy(dibh->b_data + sizeof(struct gfs2_dinode), symname,
362 size);
363 brelse(dibh);
364 }
365
366 gfs2_trans_end(sdp);
367 if (dip->i_alloc.al_rgd)
368 gfs2_inplace_release(dip);
369 gfs2_quota_unlock(dip);
370 gfs2_alloc_put(dip);
371
372 gfs2_glock_dq_uninit_m(2, ghs);
373
David Teiglandb3b94fa2006-01-16 16:50:04 +0000374 d_instantiate(dentry, inode);
375 mark_inode_dirty(inode);
376
377 return 0;
378}
379
380/**
381 * gfs2_mkdir - Make a directory
382 * @dir: The parent directory of the new one
383 * @dentry: The dentry of the new directory
384 * @mode: The mode of the new directory
385 *
386 * Returns: errno
387 */
388
389static int gfs2_mkdir(struct inode *dir, struct dentry *dentry, int mode)
390{
Steven Whitehouse5c676f62006-02-27 17:23:27 -0500391 struct gfs2_inode *dip = dir->u.generic_ip, *ip;
David Teiglandb3b94fa2006-01-16 16:50:04 +0000392 struct gfs2_sbd *sdp = dip->i_sbd;
393 struct gfs2_holder ghs[2];
394 struct inode *inode;
395 struct buffer_head *dibh;
396 int error;
397
David Teiglandb3b94fa2006-01-16 16:50:04 +0000398 gfs2_holder_init(dip->i_gl, 0, 0, ghs);
399
Steven Whitehouse7359a192006-02-13 12:27:43 +0000400 inode = gfs2_createi(ghs, &dentry->d_name, S_IFDIR | mode);
401 if (IS_ERR(inode)) {
David Teiglandb3b94fa2006-01-16 16:50:04 +0000402 gfs2_holder_uninit(ghs);
Steven Whitehouse7359a192006-02-13 12:27:43 +0000403 return PTR_ERR(inode);
David Teiglandb3b94fa2006-01-16 16:50:04 +0000404 }
405
Steven Whitehouse5c676f62006-02-27 17:23:27 -0500406 ip = ghs[1].gh_gl->gl_object;
David Teiglandb3b94fa2006-01-16 16:50:04 +0000407
408 ip->i_di.di_nlink = 2;
409 ip->i_di.di_size = sdp->sd_sb.sb_bsize - sizeof(struct gfs2_dinode);
410 ip->i_di.di_flags |= GFS2_DIF_JDATA;
411 ip->i_di.di_payload_format = GFS2_FORMAT_DE;
412 ip->i_di.di_entries = 2;
413
414 error = gfs2_meta_inode_buffer(ip, &dibh);
415
416 if (!gfs2_assert_withdraw(sdp, !error)) {
417 struct gfs2_dinode *di = (struct gfs2_dinode *)dibh->b_data;
Steven Whitehousec7526662006-03-20 12:30:04 -0500418 struct gfs2_dirent *dent = (struct gfs2_dirent *)(di+1);
Steven Whitehouse71b86f52006-03-28 14:14:04 -0500419 struct qstr str;
David Teiglandb3b94fa2006-01-16 16:50:04 +0000420
Steven Whitehouse71b86f52006-03-28 14:14:04 -0500421 gfs2_str2qstr(&str, ".");
Steven Whitehousec7526662006-03-20 12:30:04 -0500422 gfs2_trans_add_bh(ip->i_gl, dibh, 1);
423 gfs2_qstr2dirent(&str, GFS2_DIRENT_SIZE(str.len), dent);
David Teiglandb3b94fa2006-01-16 16:50:04 +0000424 dent->de_inum = di->di_num; /* already GFS2 endian */
David Teiglandb3b94fa2006-01-16 16:50:04 +0000425 dent->de_type = DT_DIR;
David Teiglandb3b94fa2006-01-16 16:50:04 +0000426 di->di_entries = cpu_to_be32(1);
427
Steven Whitehouse71b86f52006-03-28 14:14:04 -0500428 gfs2_str2qstr(&str, "..");
Steven Whitehousec7526662006-03-20 12:30:04 -0500429 dent = (struct gfs2_dirent *)((char*)dent + GFS2_DIRENT_SIZE(1));
430 gfs2_qstr2dirent(&str, dibh->b_size - GFS2_DIRENT_SIZE(1) - sizeof(struct gfs2_dinode), dent);
David Teiglandb3b94fa2006-01-16 16:50:04 +0000431
432 gfs2_inum_out(&dip->i_num, (char *) &dent->de_inum);
David Teiglandb3b94fa2006-01-16 16:50:04 +0000433 dent->de_type = DT_DIR;
David Teiglandb3b94fa2006-01-16 16:50:04 +0000434
435 gfs2_dinode_out(&ip->i_di, (char *)di);
436
437 brelse(dibh);
438 }
439
440 error = gfs2_change_nlink(dip, +1);
441 gfs2_assert_withdraw(sdp, !error); /* dip already pinned */
442
443 gfs2_trans_end(sdp);
444 if (dip->i_alloc.al_rgd)
445 gfs2_inplace_release(dip);
446 gfs2_quota_unlock(dip);
447 gfs2_alloc_put(dip);
448
449 gfs2_glock_dq_uninit_m(2, ghs);
450
David Teiglandb3b94fa2006-01-16 16:50:04 +0000451 d_instantiate(dentry, inode);
452 mark_inode_dirty(inode);
453
454 return 0;
455}
456
457/**
458 * gfs2_rmdir - Remove a directory
459 * @dir: The parent directory of the directory to be removed
460 * @dentry: The dentry of the directory to remove
461 *
462 * Remove a directory. Call gfs2_rmdiri()
463 *
464 * Returns: errno
465 */
466
467static int gfs2_rmdir(struct inode *dir, struct dentry *dentry)
468{
Steven Whitehouse5c676f62006-02-27 17:23:27 -0500469 struct gfs2_inode *dip = dir->u.generic_ip;
David Teiglandb3b94fa2006-01-16 16:50:04 +0000470 struct gfs2_sbd *sdp = dip->i_sbd;
Steven Whitehouse5c676f62006-02-27 17:23:27 -0500471 struct gfs2_inode *ip = dentry->d_inode->u.generic_ip;
David Teiglandb3b94fa2006-01-16 16:50:04 +0000472 struct gfs2_unlinked *ul;
473 struct gfs2_holder ghs[2];
474 int error;
475
David Teiglandb3b94fa2006-01-16 16:50:04 +0000476 error = gfs2_unlinked_get(sdp, &ul);
477 if (error)
478 return error;
479
480 gfs2_holder_init(dip->i_gl, LM_ST_EXCLUSIVE, 0, ghs);
481 gfs2_holder_init(ip->i_gl, LM_ST_EXCLUSIVE, 0, ghs + 1);
482
483 error = gfs2_glock_nq_m(2, ghs);
484 if (error)
485 goto out;
486
487 error = gfs2_unlink_ok(dip, &dentry->d_name, ip);
488 if (error)
489 goto out_gunlock;
490
491 if (ip->i_di.di_entries < 2) {
492 if (gfs2_consist_inode(ip))
493 gfs2_dinode_print(&ip->i_di);
494 error = -EIO;
495 goto out_gunlock;
496 }
497 if (ip->i_di.di_entries > 2) {
498 error = -ENOTEMPTY;
499 goto out_gunlock;
500 }
501
502 error = gfs2_trans_begin(sdp, 2 * RES_DINODE + 3 * RES_LEAF +
503 RES_UNLINKED, 0);
504 if (error)
505 goto out_gunlock;
506
507 error = gfs2_rmdiri(dip, &dentry->d_name, ip, ul);
508
509 gfs2_trans_end(sdp);
510
511 out_gunlock:
512 gfs2_glock_dq_m(2, ghs);
513
514 out:
515 gfs2_holder_uninit(ghs);
516 gfs2_holder_uninit(ghs + 1);
517
518 gfs2_unlinked_put(sdp, ul);
519
520 return error;
521}
522
523/**
524 * gfs2_mknod - Make a special file
525 * @dir: The directory in which the special file will reside
526 * @dentry: The dentry of the special file
527 * @mode: The mode of the special file
528 * @rdev: The device specification of the special file
529 *
530 */
531
532static int gfs2_mknod(struct inode *dir, struct dentry *dentry, int mode,
533 dev_t dev)
534{
Steven Whitehouse5c676f62006-02-27 17:23:27 -0500535 struct gfs2_inode *dip = dir->u.generic_ip, *ip;
David Teiglandb3b94fa2006-01-16 16:50:04 +0000536 struct gfs2_sbd *sdp = dip->i_sbd;
537 struct gfs2_holder ghs[2];
538 struct inode *inode;
539 struct buffer_head *dibh;
540 uint32_t major = 0, minor = 0;
541 int error;
542
David Teiglandb3b94fa2006-01-16 16:50:04 +0000543 switch (mode & S_IFMT) {
544 case S_IFBLK:
545 case S_IFCHR:
546 major = MAJOR(dev);
547 minor = MINOR(dev);
548 break;
549 case S_IFIFO:
550 case S_IFSOCK:
551 break;
552 default:
553 return -EOPNOTSUPP;
554 };
555
556 gfs2_holder_init(dip->i_gl, 0, 0, ghs);
557
Steven Whitehouse7359a192006-02-13 12:27:43 +0000558 inode = gfs2_createi(ghs, &dentry->d_name, mode);
559 if (IS_ERR(inode)) {
David Teiglandb3b94fa2006-01-16 16:50:04 +0000560 gfs2_holder_uninit(ghs);
Steven Whitehouse7359a192006-02-13 12:27:43 +0000561 return PTR_ERR(inode);
David Teiglandb3b94fa2006-01-16 16:50:04 +0000562 }
563
Steven Whitehouse5c676f62006-02-27 17:23:27 -0500564 ip = ghs[1].gh_gl->gl_object;
David Teiglandb3b94fa2006-01-16 16:50:04 +0000565
566 ip->i_di.di_major = major;
567 ip->i_di.di_minor = minor;
568
569 error = gfs2_meta_inode_buffer(ip, &dibh);
570
571 if (!gfs2_assert_withdraw(sdp, !error)) {
572 gfs2_dinode_out(&ip->i_di, dibh->b_data);
573 brelse(dibh);
574 }
575
576 gfs2_trans_end(sdp);
577 if (dip->i_alloc.al_rgd)
578 gfs2_inplace_release(dip);
579 gfs2_quota_unlock(dip);
580 gfs2_alloc_put(dip);
581
582 gfs2_glock_dq_uninit_m(2, ghs);
583
David Teiglandb3b94fa2006-01-16 16:50:04 +0000584 d_instantiate(dentry, inode);
585 mark_inode_dirty(inode);
586
587 return 0;
588}
589
590/**
591 * gfs2_rename - Rename a file
592 * @odir: Parent directory of old file name
593 * @odentry: The old dentry of the file
594 * @ndir: Parent directory of new file name
595 * @ndentry: The new dentry of the file
596 *
597 * Returns: errno
598 */
599
600static int gfs2_rename(struct inode *odir, struct dentry *odentry,
601 struct inode *ndir, struct dentry *ndentry)
602{
Steven Whitehouse5c676f62006-02-27 17:23:27 -0500603 struct gfs2_inode *odip = odir->u.generic_ip;
604 struct gfs2_inode *ndip = ndir->u.generic_ip;
605 struct gfs2_inode *ip = odentry->d_inode->u.generic_ip;
David Teiglandb3b94fa2006-01-16 16:50:04 +0000606 struct gfs2_inode *nip = NULL;
607 struct gfs2_sbd *sdp = odip->i_sbd;
608 struct gfs2_unlinked *ul;
609 struct gfs2_holder ghs[4], r_gh;
610 unsigned int num_gh;
611 int dir_rename = 0;
612 int alloc_required;
613 unsigned int x;
614 int error;
615
David Teiglandb3b94fa2006-01-16 16:50:04 +0000616 if (ndentry->d_inode) {
Steven Whitehouse5c676f62006-02-27 17:23:27 -0500617 nip = ndentry->d_inode->u.generic_ip;
David Teiglandb3b94fa2006-01-16 16:50:04 +0000618 if (ip == nip)
619 return 0;
620 }
621
622 error = gfs2_unlinked_get(sdp, &ul);
623 if (error)
624 return error;
625
626 /* Make sure we aren't trying to move a dirctory into it's subdir */
627
628 if (S_ISDIR(ip->i_di.di_mode) && odip != ndip) {
629 dir_rename = 1;
630
631 error = gfs2_glock_nq_init(sdp->sd_rename_gl,
632 LM_ST_EXCLUSIVE, 0,
633 &r_gh);
634 if (error)
635 goto out;
636
637 error = gfs2_ok_to_move(ip, ndip);
638 if (error)
639 goto out_gunlock_r;
640 }
641
642 gfs2_holder_init(odip->i_gl, LM_ST_EXCLUSIVE, 0, ghs);
643 gfs2_holder_init(ndip->i_gl, LM_ST_EXCLUSIVE, 0, ghs + 1);
644 gfs2_holder_init(ip->i_gl, LM_ST_EXCLUSIVE, 0, ghs + 2);
645 num_gh = 3;
646
647 if (nip)
648 gfs2_holder_init(nip->i_gl, LM_ST_EXCLUSIVE, 0, ghs + num_gh++);
649
650 error = gfs2_glock_nq_m(num_gh, ghs);
651 if (error)
652 goto out_uninit;
653
654 /* Check out the old directory */
655
656 error = gfs2_unlink_ok(odip, &odentry->d_name, ip);
657 if (error)
658 goto out_gunlock;
659
660 /* Check out the new directory */
661
662 if (nip) {
663 error = gfs2_unlink_ok(ndip, &ndentry->d_name, nip);
664 if (error)
665 goto out_gunlock;
666
667 if (S_ISDIR(nip->i_di.di_mode)) {
668 if (nip->i_di.di_entries < 2) {
669 if (gfs2_consist_inode(nip))
670 gfs2_dinode_print(&nip->i_di);
671 error = -EIO;
672 goto out_gunlock;
673 }
674 if (nip->i_di.di_entries > 2) {
675 error = -ENOTEMPTY;
676 goto out_gunlock;
677 }
678 }
679 } else {
680 error = gfs2_repermission(ndir, MAY_WRITE | MAY_EXEC, NULL);
681 if (error)
682 goto out_gunlock;
683
Steven Whitehousec7526662006-03-20 12:30:04 -0500684 error = gfs2_dir_search(ndir, &ndentry->d_name, NULL, NULL);
David Teiglandb3b94fa2006-01-16 16:50:04 +0000685 switch (error) {
686 case -ENOENT:
687 error = 0;
688 break;
689 case 0:
690 error = -EEXIST;
691 default:
692 goto out_gunlock;
693 };
694
695 if (odip != ndip) {
696 if (!ndip->i_di.di_nlink) {
697 error = -EINVAL;
698 goto out_gunlock;
699 }
700 if (ndip->i_di.di_entries == (uint32_t)-1) {
701 error = -EFBIG;
702 goto out_gunlock;
703 }
704 if (S_ISDIR(ip->i_di.di_mode) &&
705 ndip->i_di.di_nlink == (uint32_t)-1) {
706 error = -EMLINK;
707 goto out_gunlock;
708 }
709 }
710 }
711
712 /* Check out the dir to be renamed */
713
714 if (dir_rename) {
715 error = gfs2_repermission(odentry->d_inode, MAY_WRITE, NULL);
716 if (error)
717 goto out_gunlock;
718 }
719
Steven Whitehousec7526662006-03-20 12:30:04 -0500720 alloc_required = error = gfs2_diradd_alloc_required(ndir, &ndentry->d_name);
721 if (error < 0)
David Teiglandb3b94fa2006-01-16 16:50:04 +0000722 goto out_gunlock;
Steven Whitehousec7526662006-03-20 12:30:04 -0500723 error = 0;
David Teiglandb3b94fa2006-01-16 16:50:04 +0000724
725 if (alloc_required) {
726 struct gfs2_alloc *al = gfs2_alloc_get(ndip);
727
728 error = gfs2_quota_lock(ndip, NO_QUOTA_CHANGE, NO_QUOTA_CHANGE);
729 if (error)
730 goto out_alloc;
731
732 error = gfs2_quota_check(ndip, ndip->i_di.di_uid,
733 ndip->i_di.di_gid);
734 if (error)
735 goto out_gunlock_q;
736
737 al->al_requested = sdp->sd_max_dirres;
738
739 error = gfs2_inplace_reserve(ndip);
740 if (error)
741 goto out_gunlock_q;
742
Steven Whitehousefe1bded2006-04-18 10:09:15 -0400743 error = gfs2_trans_begin(sdp, sdp->sd_max_dirres +
David Teiglandb3b94fa2006-01-16 16:50:04 +0000744 al->al_rgd->rd_ri.ri_length +
745 4 * RES_DINODE + 4 * RES_LEAF +
746 RES_UNLINKED + RES_STATFS +
747 RES_QUOTA, 0);
748 if (error)
749 goto out_ipreserv;
750 } else {
751 error = gfs2_trans_begin(sdp, 4 * RES_DINODE +
752 5 * RES_LEAF +
753 RES_UNLINKED, 0);
754 if (error)
755 goto out_gunlock;
756 }
757
758 /* Remove the target file, if it exists */
759
760 if (nip) {
761 if (S_ISDIR(nip->i_di.di_mode))
762 error = gfs2_rmdiri(ndip, &ndentry->d_name, nip, ul);
763 else
764 error = gfs2_unlinki(ndip, &ndentry->d_name, nip, ul);
765 if (error)
766 goto out_end_trans;
767 }
768
769 if (dir_rename) {
770 struct qstr name;
Steven Whitehouse71b86f52006-03-28 14:14:04 -0500771 gfs2_str2qstr(&name, "..");
David Teiglandb3b94fa2006-01-16 16:50:04 +0000772
773 error = gfs2_change_nlink(ndip, +1);
774 if (error)
775 goto out_end_trans;
776 error = gfs2_change_nlink(odip, -1);
777 if (error)
778 goto out_end_trans;
779
780 error = gfs2_dir_mvino(ip, &name, &ndip->i_num, DT_DIR);
781 if (error)
782 goto out_end_trans;
783 } else {
784 struct buffer_head *dibh;
785 error = gfs2_meta_inode_buffer(ip, &dibh);
786 if (error)
787 goto out_end_trans;
788 ip->i_di.di_ctime = get_seconds();
Steven Whitehoused4e9c4c2006-01-18 11:19:28 +0000789 gfs2_trans_add_bh(ip->i_gl, dibh, 1);
David Teiglandb3b94fa2006-01-16 16:50:04 +0000790 gfs2_dinode_out(&ip->i_di, dibh->b_data);
791 brelse(dibh);
792 }
793
794 error = gfs2_dir_del(odip, &odentry->d_name);
795 if (error)
796 goto out_end_trans;
797
Steven Whitehousec7526662006-03-20 12:30:04 -0500798 error = gfs2_dir_add(ndir, &ndentry->d_name, &ip->i_num,
David Teiglandb3b94fa2006-01-16 16:50:04 +0000799 IF2DT(ip->i_di.di_mode));
800 if (error)
801 goto out_end_trans;
802
803 out_end_trans:
804 gfs2_trans_end(sdp);
805
806 out_ipreserv:
807 if (alloc_required)
808 gfs2_inplace_release(ndip);
809
810 out_gunlock_q:
811 if (alloc_required)
812 gfs2_quota_unlock(ndip);
813
814 out_alloc:
815 if (alloc_required)
816 gfs2_alloc_put(ndip);
817
818 out_gunlock:
819 gfs2_glock_dq_m(num_gh, ghs);
820
821 out_uninit:
822 for (x = 0; x < num_gh; x++)
823 gfs2_holder_uninit(ghs + x);
824
825 out_gunlock_r:
826 if (dir_rename)
827 gfs2_glock_dq_uninit(&r_gh);
828
829 out:
830 gfs2_unlinked_put(sdp, ul);
831
832 return error;
833}
834
835/**
836 * gfs2_readlink - Read the value of a symlink
837 * @dentry: the symlink
838 * @buf: the buffer to read the symlink data into
839 * @size: the size of the buffer
840 *
841 * Returns: errno
842 */
843
844static int gfs2_readlink(struct dentry *dentry, char __user *user_buf,
845 int user_size)
846{
Steven Whitehouse5c676f62006-02-27 17:23:27 -0500847 struct gfs2_inode *ip = dentry->d_inode->u.generic_ip;
David Teiglandb3b94fa2006-01-16 16:50:04 +0000848 char array[GFS2_FAST_NAME_SIZE], *buf = array;
849 unsigned int len = GFS2_FAST_NAME_SIZE;
850 int error;
851
David Teiglandb3b94fa2006-01-16 16:50:04 +0000852 error = gfs2_readlinki(ip, &buf, &len);
853 if (error)
854 return error;
855
856 if (user_size > len - 1)
857 user_size = len - 1;
858
859 if (copy_to_user(user_buf, buf, user_size))
860 error = -EFAULT;
861 else
862 error = user_size;
863
864 if (buf != array)
865 kfree(buf);
866
867 return error;
868}
869
870/**
871 * gfs2_follow_link - Follow a symbolic link
872 * @dentry: The dentry of the link
873 * @nd: Data that we pass to vfs_follow_link()
874 *
875 * This can handle symlinks of any size. It is optimised for symlinks
876 * under GFS2_FAST_NAME_SIZE.
877 *
878 * Returns: 0 on success or error code
879 */
880
881static void *gfs2_follow_link(struct dentry *dentry, struct nameidata *nd)
882{
Steven Whitehouse5c676f62006-02-27 17:23:27 -0500883 struct gfs2_inode *ip = dentry->d_inode->u.generic_ip;
David Teiglandb3b94fa2006-01-16 16:50:04 +0000884 char array[GFS2_FAST_NAME_SIZE], *buf = array;
885 unsigned int len = GFS2_FAST_NAME_SIZE;
886 int error;
887
David Teiglandb3b94fa2006-01-16 16:50:04 +0000888 error = gfs2_readlinki(ip, &buf, &len);
889 if (!error) {
890 error = vfs_follow_link(nd, buf);
891 if (buf != array)
892 kfree(buf);
893 }
894
895 return ERR_PTR(error);
896}
897
898/**
899 * gfs2_permission -
900 * @inode:
901 * @mask:
902 * @nd: passed from Linux VFS, ignored by us
903 *
904 * Returns: errno
905 */
906
907static int gfs2_permission(struct inode *inode, int mask, struct nameidata *nd)
908{
Steven Whitehouse5c676f62006-02-27 17:23:27 -0500909 struct gfs2_inode *ip = inode->u.generic_ip;
David Teiglandb3b94fa2006-01-16 16:50:04 +0000910 struct gfs2_holder i_gh;
911 int error;
912
David Teiglandb3b94fa2006-01-16 16:50:04 +0000913 if (ip->i_vn == ip->i_gl->gl_vn)
914 return generic_permission(inode, mask, gfs2_check_acl);
915
916 error = gfs2_glock_nq_init(ip->i_gl,
917 LM_ST_SHARED, LM_FLAG_ANY,
918 &i_gh);
919 if (!error) {
920 error = generic_permission(inode, mask, gfs2_check_acl_locked);
921 gfs2_glock_dq_uninit(&i_gh);
922 }
923
924 return error;
925}
926
927static int setattr_size(struct inode *inode, struct iattr *attr)
928{
Steven Whitehouse5c676f62006-02-27 17:23:27 -0500929 struct gfs2_inode *ip = inode->u.generic_ip;
David Teiglandb3b94fa2006-01-16 16:50:04 +0000930 int error;
931
932 if (attr->ia_size != ip->i_di.di_size) {
933 error = vmtruncate(inode, attr->ia_size);
934 if (error)
935 return error;
936 }
937
Steven Whitehouseaa6a85a2006-01-24 10:37:06 +0000938 error = gfs2_truncatei(ip, attr->ia_size);
David Teiglandb3b94fa2006-01-16 16:50:04 +0000939 if (error)
940 return error;
941
942 return error;
943}
944
945static int setattr_chown(struct inode *inode, struct iattr *attr)
946{
Steven Whitehouse5c676f62006-02-27 17:23:27 -0500947 struct gfs2_inode *ip = inode->u.generic_ip;
David Teiglandb3b94fa2006-01-16 16:50:04 +0000948 struct gfs2_sbd *sdp = ip->i_sbd;
949 struct buffer_head *dibh;
950 uint32_t ouid, ogid, nuid, ngid;
951 int error;
952
953 ouid = ip->i_di.di_uid;
954 ogid = ip->i_di.di_gid;
955 nuid = attr->ia_uid;
956 ngid = attr->ia_gid;
957
958 if (!(attr->ia_valid & ATTR_UID) || ouid == nuid)
959 ouid = nuid = NO_QUOTA_CHANGE;
960 if (!(attr->ia_valid & ATTR_GID) || ogid == ngid)
961 ogid = ngid = NO_QUOTA_CHANGE;
962
963 gfs2_alloc_get(ip);
964
965 error = gfs2_quota_lock(ip, nuid, ngid);
966 if (error)
967 goto out_alloc;
968
969 if (ouid != NO_QUOTA_CHANGE || ogid != NO_QUOTA_CHANGE) {
970 error = gfs2_quota_check(ip, nuid, ngid);
971 if (error)
972 goto out_gunlock_q;
973 }
974
975 error = gfs2_trans_begin(sdp, RES_DINODE + 2 * RES_QUOTA, 0);
976 if (error)
977 goto out_gunlock_q;
978
979 error = gfs2_meta_inode_buffer(ip, &dibh);
980 if (error)
981 goto out_end_trans;
982
983 error = inode_setattr(inode, attr);
984 gfs2_assert_warn(sdp, !error);
985 gfs2_inode_attr_out(ip);
986
Steven Whitehoused4e9c4c2006-01-18 11:19:28 +0000987 gfs2_trans_add_bh(ip->i_gl, dibh, 1);
David Teiglandb3b94fa2006-01-16 16:50:04 +0000988 gfs2_dinode_out(&ip->i_di, dibh->b_data);
989 brelse(dibh);
990
991 if (ouid != NO_QUOTA_CHANGE || ogid != NO_QUOTA_CHANGE) {
992 gfs2_quota_change(ip, -ip->i_di.di_blocks,
993 ouid, ogid);
994 gfs2_quota_change(ip, ip->i_di.di_blocks,
995 nuid, ngid);
996 }
997
998 out_end_trans:
999 gfs2_trans_end(sdp);
1000
1001 out_gunlock_q:
1002 gfs2_quota_unlock(ip);
1003
1004 out_alloc:
1005 gfs2_alloc_put(ip);
1006
1007 return error;
1008}
1009
1010/**
1011 * gfs2_setattr - Change attributes on an inode
1012 * @dentry: The dentry which is changing
1013 * @attr: The structure describing the change
1014 *
1015 * The VFS layer wants to change one or more of an inodes attributes. Write
1016 * that change out to disk.
1017 *
1018 * Returns: errno
1019 */
1020
1021static int gfs2_setattr(struct dentry *dentry, struct iattr *attr)
1022{
1023 struct inode *inode = dentry->d_inode;
Steven Whitehouse5c676f62006-02-27 17:23:27 -05001024 struct gfs2_inode *ip = inode->u.generic_ip;
David Teiglandb3b94fa2006-01-16 16:50:04 +00001025 struct gfs2_holder i_gh;
1026 int error;
1027
David Teiglandb3b94fa2006-01-16 16:50:04 +00001028 error = gfs2_glock_nq_init(ip->i_gl, LM_ST_EXCLUSIVE, 0, &i_gh);
1029 if (error)
1030 return error;
1031
1032 error = -EPERM;
1033 if (IS_IMMUTABLE(inode) || IS_APPEND(inode))
1034 goto out;
1035
1036 error = inode_change_ok(inode, attr);
1037 if (error)
1038 goto out;
1039
1040 if (attr->ia_valid & ATTR_SIZE)
1041 error = setattr_size(inode, attr);
1042 else if (attr->ia_valid & (ATTR_UID | ATTR_GID))
1043 error = setattr_chown(inode, attr);
1044 else if ((attr->ia_valid & ATTR_MODE) && IS_POSIXACL(inode))
1045 error = gfs2_acl_chmod(ip, attr);
1046 else
1047 error = gfs2_setattr_simple(ip, attr);
1048
1049 out:
1050 gfs2_glock_dq_uninit(&i_gh);
1051
1052 if (!error)
1053 mark_inode_dirty(inode);
1054
1055 return error;
1056}
1057
1058/**
1059 * gfs2_getattr - Read out an inode's attributes
1060 * @mnt: ?
1061 * @dentry: The dentry to stat
1062 * @stat: The inode's stats
1063 *
1064 * Returns: errno
1065 */
1066
1067static int gfs2_getattr(struct vfsmount *mnt, struct dentry *dentry,
1068 struct kstat *stat)
1069{
1070 struct inode *inode = dentry->d_inode;
Steven Whitehouse5c676f62006-02-27 17:23:27 -05001071 struct gfs2_inode *ip = inode->u.generic_ip;
David Teiglandb3b94fa2006-01-16 16:50:04 +00001072 struct gfs2_holder gh;
1073 int error;
1074
David Teiglandb3b94fa2006-01-16 16:50:04 +00001075 error = gfs2_glock_nq_init(ip->i_gl, LM_ST_SHARED, LM_FLAG_ANY, &gh);
1076 if (!error) {
1077 generic_fillattr(inode, stat);
1078 gfs2_glock_dq_uninit(&gh);
1079 }
1080
1081 return error;
1082}
1083
1084static int gfs2_setxattr(struct dentry *dentry, const char *name,
1085 const void *data, size_t size, int flags)
1086{
Steven Whitehouse5c676f62006-02-27 17:23:27 -05001087 struct gfs2_inode *ip = dentry->d_inode->u.generic_ip;
David Teiglandb3b94fa2006-01-16 16:50:04 +00001088 struct gfs2_ea_request er;
1089
David Teiglandb3b94fa2006-01-16 16:50:04 +00001090 memset(&er, 0, sizeof(struct gfs2_ea_request));
1091 er.er_type = gfs2_ea_name2type(name, &er.er_name);
1092 if (er.er_type == GFS2_EATYPE_UNUSED)
1093 return -EOPNOTSUPP;
1094 er.er_data = (char *)data;
1095 er.er_name_len = strlen(er.er_name);
1096 er.er_data_len = size;
1097 er.er_flags = flags;
1098
1099 gfs2_assert_warn(ip->i_sbd, !(er.er_flags & GFS2_ERF_MODE));
1100
1101 return gfs2_ea_set(ip, &er);
1102}
1103
1104static ssize_t gfs2_getxattr(struct dentry *dentry, const char *name,
1105 void *data, size_t size)
1106{
1107 struct gfs2_ea_request er;
1108
David Teiglandb3b94fa2006-01-16 16:50:04 +00001109 memset(&er, 0, sizeof(struct gfs2_ea_request));
1110 er.er_type = gfs2_ea_name2type(name, &er.er_name);
1111 if (er.er_type == GFS2_EATYPE_UNUSED)
1112 return -EOPNOTSUPP;
1113 er.er_data = data;
1114 er.er_name_len = strlen(er.er_name);
1115 er.er_data_len = size;
1116
Steven Whitehouse5c676f62006-02-27 17:23:27 -05001117 return gfs2_ea_get(dentry->d_inode->u.generic_ip, &er);
David Teiglandb3b94fa2006-01-16 16:50:04 +00001118}
1119
1120static ssize_t gfs2_listxattr(struct dentry *dentry, char *buffer, size_t size)
1121{
1122 struct gfs2_ea_request er;
1123
David Teiglandb3b94fa2006-01-16 16:50:04 +00001124 memset(&er, 0, sizeof(struct gfs2_ea_request));
1125 er.er_data = (size) ? buffer : NULL;
1126 er.er_data_len = size;
1127
Steven Whitehouse5c676f62006-02-27 17:23:27 -05001128 return gfs2_ea_list(dentry->d_inode->u.generic_ip, &er);
David Teiglandb3b94fa2006-01-16 16:50:04 +00001129}
1130
1131static int gfs2_removexattr(struct dentry *dentry, const char *name)
1132{
1133 struct gfs2_ea_request er;
1134
David Teiglandb3b94fa2006-01-16 16:50:04 +00001135 memset(&er, 0, sizeof(struct gfs2_ea_request));
1136 er.er_type = gfs2_ea_name2type(name, &er.er_name);
1137 if (er.er_type == GFS2_EATYPE_UNUSED)
1138 return -EOPNOTSUPP;
1139 er.er_name_len = strlen(er.er_name);
1140
Steven Whitehouse5c676f62006-02-27 17:23:27 -05001141 return gfs2_ea_remove(dentry->d_inode->u.generic_ip, &er);
David Teiglandb3b94fa2006-01-16 16:50:04 +00001142}
1143
1144struct inode_operations gfs2_file_iops = {
1145 .permission = gfs2_permission,
1146 .setattr = gfs2_setattr,
1147 .getattr = gfs2_getattr,
1148 .setxattr = gfs2_setxattr,
1149 .getxattr = gfs2_getxattr,
1150 .listxattr = gfs2_listxattr,
1151 .removexattr = gfs2_removexattr,
1152};
1153
1154struct inode_operations gfs2_dev_iops = {
1155 .permission = gfs2_permission,
1156 .setattr = gfs2_setattr,
1157 .getattr = gfs2_getattr,
1158 .setxattr = gfs2_setxattr,
1159 .getxattr = gfs2_getxattr,
1160 .listxattr = gfs2_listxattr,
1161 .removexattr = gfs2_removexattr,
1162};
1163
1164struct inode_operations gfs2_dir_iops = {
1165 .create = gfs2_create,
1166 .lookup = gfs2_lookup,
1167 .link = gfs2_link,
1168 .unlink = gfs2_unlink,
1169 .symlink = gfs2_symlink,
1170 .mkdir = gfs2_mkdir,
1171 .rmdir = gfs2_rmdir,
1172 .mknod = gfs2_mknod,
1173 .rename = gfs2_rename,
1174 .permission = gfs2_permission,
1175 .setattr = gfs2_setattr,
1176 .getattr = gfs2_getattr,
1177 .setxattr = gfs2_setxattr,
1178 .getxattr = gfs2_getxattr,
1179 .listxattr = gfs2_listxattr,
1180 .removexattr = gfs2_removexattr,
1181};
1182
1183struct inode_operations gfs2_symlink_iops = {
1184 .readlink = gfs2_readlink,
1185 .follow_link = gfs2_follow_link,
1186 .permission = gfs2_permission,
1187 .setattr = gfs2_setattr,
1188 .getattr = gfs2_getattr,
1189 .setxattr = gfs2_setxattr,
1190 .getxattr = gfs2_getxattr,
1191 .listxattr = gfs2_listxattr,
1192 .removexattr = gfs2_removexattr,
1193};
1194