new helper: ihold()
[linux-2.6.git] / fs / exofs / namei.c
1 /*
2  * Copyright (C) 2005, 2006
3  * Avishay Traeger (avishay@gmail.com)
4  * Copyright (C) 2008, 2009
5  * Boaz Harrosh <bharrosh@panasas.com>
6  *
7  * Copyrights for code taken from ext2:
8  *     Copyright (C) 1992, 1993, 1994, 1995
9  *     Remy Card (card@masi.ibp.fr)
10  *     Laboratoire MASI - Institut Blaise Pascal
11  *     Universite Pierre et Marie Curie (Paris VI)
12  *     from
13  *     linux/fs/minix/inode.c
14  *     Copyright (C) 1991, 1992  Linus Torvalds
15  *
16  * This file is part of exofs.
17  *
18  * exofs is free software; you can redistribute it and/or modify
19  * it under the terms of the GNU General Public License as published by
20  * the Free Software Foundation.  Since it is based on ext2, and the only
21  * valid version of GPL for the Linux kernel is version 2, the only valid
22  * version of GPL for exofs is version 2.
23  *
24  * exofs is distributed in the hope that it will be useful,
25  * but WITHOUT ANY WARRANTY; without even the implied warranty of
26  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
27  * GNU General Public License for more details.
28  *
29  * You should have received a copy of the GNU General Public License
30  * along with exofs; if not, write to the Free Software
31  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
32  */
33
34 #include "exofs.h"
35
36 static inline int exofs_add_nondir(struct dentry *dentry, struct inode *inode)
37 {
38         int err = exofs_add_link(dentry, inode);
39         if (!err) {
40                 d_instantiate(dentry, inode);
41                 return 0;
42         }
43         inode_dec_link_count(inode);
44         iput(inode);
45         return err;
46 }
47
48 static struct dentry *exofs_lookup(struct inode *dir, struct dentry *dentry,
49                                    struct nameidata *nd)
50 {
51         struct inode *inode;
52         ino_t ino;
53
54         if (dentry->d_name.len > EXOFS_NAME_LEN)
55                 return ERR_PTR(-ENAMETOOLONG);
56
57         ino = exofs_inode_by_name(dir, dentry);
58         inode = NULL;
59         if (ino) {
60                 inode = exofs_iget(dir->i_sb, ino);
61                 if (IS_ERR(inode))
62                         return ERR_CAST(inode);
63         }
64         return d_splice_alias(inode, dentry);
65 }
66
67 static int exofs_create(struct inode *dir, struct dentry *dentry, int mode,
68                          struct nameidata *nd)
69 {
70         struct inode *inode = exofs_new_inode(dir, mode);
71         int err = PTR_ERR(inode);
72         if (!IS_ERR(inode)) {
73                 inode->i_op = &exofs_file_inode_operations;
74                 inode->i_fop = &exofs_file_operations;
75                 inode->i_mapping->a_ops = &exofs_aops;
76                 mark_inode_dirty(inode);
77                 err = exofs_add_nondir(dentry, inode);
78         }
79         return err;
80 }
81
82 static int exofs_mknod(struct inode *dir, struct dentry *dentry, int mode,
83                        dev_t rdev)
84 {
85         struct inode *inode;
86         int err;
87
88         if (!new_valid_dev(rdev))
89                 return -EINVAL;
90
91         inode = exofs_new_inode(dir, mode);
92         err = PTR_ERR(inode);
93         if (!IS_ERR(inode)) {
94                 init_special_inode(inode, inode->i_mode, rdev);
95                 mark_inode_dirty(inode);
96                 err = exofs_add_nondir(dentry, inode);
97         }
98         return err;
99 }
100
101 static int exofs_symlink(struct inode *dir, struct dentry *dentry,
102                           const char *symname)
103 {
104         struct super_block *sb = dir->i_sb;
105         int err = -ENAMETOOLONG;
106         unsigned l = strlen(symname)+1;
107         struct inode *inode;
108         struct exofs_i_info *oi;
109
110         if (l > sb->s_blocksize)
111                 goto out;
112
113         inode = exofs_new_inode(dir, S_IFLNK | S_IRWXUGO);
114         err = PTR_ERR(inode);
115         if (IS_ERR(inode))
116                 goto out;
117
118         oi = exofs_i(inode);
119         if (l > sizeof(oi->i_data)) {
120                 /* slow symlink */
121                 inode->i_op = &exofs_symlink_inode_operations;
122                 inode->i_mapping->a_ops = &exofs_aops;
123                 memset(oi->i_data, 0, sizeof(oi->i_data));
124
125                 err = page_symlink(inode, symname, l);
126                 if (err)
127                         goto out_fail;
128         } else {
129                 /* fast symlink */
130                 inode->i_op = &exofs_fast_symlink_inode_operations;
131                 memcpy(oi->i_data, symname, l);
132                 inode->i_size = l-1;
133         }
134         mark_inode_dirty(inode);
135
136         err = exofs_add_nondir(dentry, inode);
137 out:
138         return err;
139
140 out_fail:
141         inode_dec_link_count(inode);
142         iput(inode);
143         goto out;
144 }
145
146 static int exofs_link(struct dentry *old_dentry, struct inode *dir,
147                 struct dentry *dentry)
148 {
149         struct inode *inode = old_dentry->d_inode;
150
151         if (inode->i_nlink >= EXOFS_LINK_MAX)
152                 return -EMLINK;
153
154         inode->i_ctime = CURRENT_TIME;
155         inode_inc_link_count(inode);
156         ihold(inode);
157
158         return exofs_add_nondir(dentry, inode);
159 }
160
161 static int exofs_mkdir(struct inode *dir, struct dentry *dentry, int mode)
162 {
163         struct inode *inode;
164         int err = -EMLINK;
165
166         if (dir->i_nlink >= EXOFS_LINK_MAX)
167                 goto out;
168
169         inode_inc_link_count(dir);
170
171         inode = exofs_new_inode(dir, S_IFDIR | mode);
172         err = PTR_ERR(inode);
173         if (IS_ERR(inode))
174                 goto out_dir;
175
176         inode->i_op = &exofs_dir_inode_operations;
177         inode->i_fop = &exofs_dir_operations;
178         inode->i_mapping->a_ops = &exofs_aops;
179
180         inode_inc_link_count(inode);
181
182         err = exofs_make_empty(inode, dir);
183         if (err)
184                 goto out_fail;
185
186         err = exofs_add_link(dentry, inode);
187         if (err)
188                 goto out_fail;
189
190         d_instantiate(dentry, inode);
191 out:
192         return err;
193
194 out_fail:
195         inode_dec_link_count(inode);
196         inode_dec_link_count(inode);
197         iput(inode);
198 out_dir:
199         inode_dec_link_count(dir);
200         goto out;
201 }
202
203 static int exofs_unlink(struct inode *dir, struct dentry *dentry)
204 {
205         struct inode *inode = dentry->d_inode;
206         struct exofs_dir_entry *de;
207         struct page *page;
208         int err = -ENOENT;
209
210         de = exofs_find_entry(dir, dentry, &page);
211         if (!de)
212                 goto out;
213
214         err = exofs_delete_entry(de, page);
215         if (err)
216                 goto out;
217
218         inode->i_ctime = dir->i_ctime;
219         inode_dec_link_count(inode);
220         err = 0;
221 out:
222         return err;
223 }
224
225 static int exofs_rmdir(struct inode *dir, struct dentry *dentry)
226 {
227         struct inode *inode = dentry->d_inode;
228         int err = -ENOTEMPTY;
229
230         if (exofs_empty_dir(inode)) {
231                 err = exofs_unlink(dir, dentry);
232                 if (!err) {
233                         inode->i_size = 0;
234                         inode_dec_link_count(inode);
235                         inode_dec_link_count(dir);
236                 }
237         }
238         return err;
239 }
240
241 static int exofs_rename(struct inode *old_dir, struct dentry *old_dentry,
242                 struct inode *new_dir, struct dentry *new_dentry)
243 {
244         struct inode *old_inode = old_dentry->d_inode;
245         struct inode *new_inode = new_dentry->d_inode;
246         struct page *dir_page = NULL;
247         struct exofs_dir_entry *dir_de = NULL;
248         struct page *old_page;
249         struct exofs_dir_entry *old_de;
250         int err = -ENOENT;
251
252         old_de = exofs_find_entry(old_dir, old_dentry, &old_page);
253         if (!old_de)
254                 goto out;
255
256         if (S_ISDIR(old_inode->i_mode)) {
257                 err = -EIO;
258                 dir_de = exofs_dotdot(old_inode, &dir_page);
259                 if (!dir_de)
260                         goto out_old;
261         }
262
263         if (new_inode) {
264                 struct page *new_page;
265                 struct exofs_dir_entry *new_de;
266
267                 err = -ENOTEMPTY;
268                 if (dir_de && !exofs_empty_dir(new_inode))
269                         goto out_dir;
270
271                 err = -ENOENT;
272                 new_de = exofs_find_entry(new_dir, new_dentry, &new_page);
273                 if (!new_de)
274                         goto out_dir;
275                 inode_inc_link_count(old_inode);
276                 err = exofs_set_link(new_dir, new_de, new_page, old_inode);
277                 new_inode->i_ctime = CURRENT_TIME;
278                 if (dir_de)
279                         drop_nlink(new_inode);
280                 inode_dec_link_count(new_inode);
281                 if (err)
282                         goto out_dir;
283         } else {
284                 if (dir_de) {
285                         err = -EMLINK;
286                         if (new_dir->i_nlink >= EXOFS_LINK_MAX)
287                                 goto out_dir;
288                 }
289                 inode_inc_link_count(old_inode);
290                 err = exofs_add_link(new_dentry, old_inode);
291                 if (err) {
292                         inode_dec_link_count(old_inode);
293                         goto out_dir;
294                 }
295                 if (dir_de)
296                         inode_inc_link_count(new_dir);
297         }
298
299         old_inode->i_ctime = CURRENT_TIME;
300
301         exofs_delete_entry(old_de, old_page);
302         inode_dec_link_count(old_inode);
303
304         if (dir_de) {
305                 err = exofs_set_link(old_inode, dir_de, dir_page, new_dir);
306                 inode_dec_link_count(old_dir);
307                 if (err)
308                         goto out_dir;
309         }
310         return 0;
311
312
313 out_dir:
314         if (dir_de) {
315                 kunmap(dir_page);
316                 page_cache_release(dir_page);
317         }
318 out_old:
319         kunmap(old_page);
320         page_cache_release(old_page);
321 out:
322         return err;
323 }
324
325 const struct inode_operations exofs_dir_inode_operations = {
326         .create         = exofs_create,
327         .lookup         = exofs_lookup,
328         .link           = exofs_link,
329         .unlink         = exofs_unlink,
330         .symlink        = exofs_symlink,
331         .mkdir          = exofs_mkdir,
332         .rmdir          = exofs_rmdir,
333         .mknod          = exofs_mknod,
334         .rename         = exofs_rename,
335         .setattr        = exofs_setattr,
336 };
337
338 const struct inode_operations exofs_special_inode_operations = {
339         .setattr        = exofs_setattr,
340 };