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