~ubuntu-branches/ubuntu/precise/linux-lowlatency/precise

« back to all changes in this revision

Viewing changes to fs/afs/inode.c

  • Committer: Package Import Robot
  • Author(s): Alessio Igor Bogani
  • Date: 2011-10-26 11:13:05 UTC
  • Revision ID: package-import@ubuntu.com-20111026111305-tz023xykf0i6eosh
Tags: upstream-3.2.0
ImportĀ upstreamĀ versionĀ 3.2.0

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * Copyright (c) 2002 Red Hat, Inc. All rights reserved.
 
3
 *
 
4
 * This software may be freely redistributed under the terms of the
 
5
 * GNU General Public License.
 
6
 *
 
7
 * You should have received a copy of the GNU General Public License
 
8
 * along with this program; if not, write to the Free Software
 
9
 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 
10
 *
 
11
 * Authors: David Woodhouse <dwmw2@infradead.org>
 
12
 *          David Howells <dhowells@redhat.com>
 
13
 *
 
14
 */
 
15
 
 
16
#include <linux/kernel.h>
 
17
#include <linux/module.h>
 
18
#include <linux/init.h>
 
19
#include <linux/fs.h>
 
20
#include <linux/pagemap.h>
 
21
#include <linux/sched.h>
 
22
#include <linux/mount.h>
 
23
#include <linux/namei.h>
 
24
#include "internal.h"
 
25
 
 
26
struct afs_iget_data {
 
27
        struct afs_fid          fid;
 
28
        struct afs_volume       *volume;        /* volume on which resides */
 
29
};
 
30
 
 
31
/*
 
32
 * map the AFS file status to the inode member variables
 
33
 */
 
34
static int afs_inode_map_status(struct afs_vnode *vnode, struct key *key)
 
35
{
 
36
        struct inode *inode = AFS_VNODE_TO_I(vnode);
 
37
 
 
38
        _debug("FS: ft=%d lk=%d sz=%llu ver=%Lu mod=%hu",
 
39
               vnode->status.type,
 
40
               vnode->status.nlink,
 
41
               (unsigned long long) vnode->status.size,
 
42
               vnode->status.data_version,
 
43
               vnode->status.mode);
 
44
 
 
45
        switch (vnode->status.type) {
 
46
        case AFS_FTYPE_FILE:
 
47
                inode->i_mode   = S_IFREG | vnode->status.mode;
 
48
                inode->i_op     = &afs_file_inode_operations;
 
49
                inode->i_fop    = &afs_file_operations;
 
50
                break;
 
51
        case AFS_FTYPE_DIR:
 
52
                inode->i_mode   = S_IFDIR | vnode->status.mode;
 
53
                inode->i_op     = &afs_dir_inode_operations;
 
54
                inode->i_fop    = &afs_dir_file_operations;
 
55
                break;
 
56
        case AFS_FTYPE_SYMLINK:
 
57
                inode->i_mode   = S_IFLNK | vnode->status.mode;
 
58
                inode->i_op     = &page_symlink_inode_operations;
 
59
                break;
 
60
        default:
 
61
                printk("kAFS: AFS vnode with undefined type\n");
 
62
                return -EBADMSG;
 
63
        }
 
64
 
 
65
#ifdef CONFIG_AFS_FSCACHE
 
66
        if (vnode->status.size != inode->i_size)
 
67
                fscache_attr_changed(vnode->cache);
 
68
#endif
 
69
 
 
70
        set_nlink(inode, vnode->status.nlink);
 
71
        inode->i_uid            = vnode->status.owner;
 
72
        inode->i_gid            = 0;
 
73
        inode->i_size           = vnode->status.size;
 
74
        inode->i_ctime.tv_sec   = vnode->status.mtime_server;
 
75
        inode->i_ctime.tv_nsec  = 0;
 
76
        inode->i_atime          = inode->i_mtime = inode->i_ctime;
 
77
        inode->i_blocks         = 0;
 
78
        inode->i_generation     = vnode->fid.unique;
 
79
        inode->i_version        = vnode->status.data_version;
 
80
        inode->i_mapping->a_ops = &afs_fs_aops;
 
81
 
 
82
        /* check to see whether a symbolic link is really a mountpoint */
 
83
        if (vnode->status.type == AFS_FTYPE_SYMLINK) {
 
84
                afs_mntpt_check_symlink(vnode, key);
 
85
 
 
86
                if (test_bit(AFS_VNODE_MOUNTPOINT, &vnode->flags)) {
 
87
                        inode->i_mode   = S_IFDIR | vnode->status.mode;
 
88
                        inode->i_op     = &afs_mntpt_inode_operations;
 
89
                        inode->i_fop    = &afs_mntpt_file_operations;
 
90
                }
 
91
        }
 
92
 
 
93
        return 0;
 
94
}
 
95
 
 
96
/*
 
97
 * iget5() comparator
 
98
 */
 
99
static int afs_iget5_test(struct inode *inode, void *opaque)
 
100
{
 
101
        struct afs_iget_data *data = opaque;
 
102
 
 
103
        return inode->i_ino == data->fid.vnode &&
 
104
                inode->i_generation == data->fid.unique;
 
105
}
 
106
 
 
107
/*
 
108
 * iget5() comparator for inode created by autocell operations
 
109
 *
 
110
 * These pseudo inodes don't match anything.
 
111
 */
 
112
static int afs_iget5_autocell_test(struct inode *inode, void *opaque)
 
113
{
 
114
        return 0;
 
115
}
 
116
 
 
117
/*
 
118
 * iget5() inode initialiser
 
119
 */
 
120
static int afs_iget5_set(struct inode *inode, void *opaque)
 
121
{
 
122
        struct afs_iget_data *data = opaque;
 
123
        struct afs_vnode *vnode = AFS_FS_I(inode);
 
124
 
 
125
        inode->i_ino = data->fid.vnode;
 
126
        inode->i_generation = data->fid.unique;
 
127
        vnode->fid = data->fid;
 
128
        vnode->volume = data->volume;
 
129
 
 
130
        return 0;
 
131
}
 
132
 
 
133
/*
 
134
 * inode retrieval for autocell
 
135
 */
 
136
struct inode *afs_iget_autocell(struct inode *dir, const char *dev_name,
 
137
                                int namesz, struct key *key)
 
138
{
 
139
        struct afs_iget_data data;
 
140
        struct afs_super_info *as;
 
141
        struct afs_vnode *vnode;
 
142
        struct super_block *sb;
 
143
        struct inode *inode;
 
144
        static atomic_t afs_autocell_ino;
 
145
 
 
146
        _enter("{%x:%u},%*.*s,",
 
147
               AFS_FS_I(dir)->fid.vid, AFS_FS_I(dir)->fid.vnode,
 
148
               namesz, namesz, dev_name ?: "");
 
149
 
 
150
        sb = dir->i_sb;
 
151
        as = sb->s_fs_info;
 
152
        data.volume = as->volume;
 
153
        data.fid.vid = as->volume->vid;
 
154
        data.fid.unique = 0;
 
155
        data.fid.vnode = 0;
 
156
 
 
157
        inode = iget5_locked(sb, atomic_inc_return(&afs_autocell_ino),
 
158
                             afs_iget5_autocell_test, afs_iget5_set,
 
159
                             &data);
 
160
        if (!inode) {
 
161
                _leave(" = -ENOMEM");
 
162
                return ERR_PTR(-ENOMEM);
 
163
        }
 
164
 
 
165
        _debug("GOT INODE %p { ino=%lu, vl=%x, vn=%x, u=%x }",
 
166
               inode, inode->i_ino, data.fid.vid, data.fid.vnode,
 
167
               data.fid.unique);
 
168
 
 
169
        vnode = AFS_FS_I(inode);
 
170
 
 
171
        /* there shouldn't be an existing inode */
 
172
        BUG_ON(!(inode->i_state & I_NEW));
 
173
 
 
174
        inode->i_size           = 0;
 
175
        inode->i_mode           = S_IFDIR | S_IRUGO | S_IXUGO;
 
176
        inode->i_op             = &afs_autocell_inode_operations;
 
177
        set_nlink(inode, 2);
 
178
        inode->i_uid            = 0;
 
179
        inode->i_gid            = 0;
 
180
        inode->i_ctime.tv_sec   = get_seconds();
 
181
        inode->i_ctime.tv_nsec  = 0;
 
182
        inode->i_atime          = inode->i_mtime = inode->i_ctime;
 
183
        inode->i_blocks         = 0;
 
184
        inode->i_version        = 0;
 
185
        inode->i_generation     = 0;
 
186
 
 
187
        set_bit(AFS_VNODE_PSEUDODIR, &vnode->flags);
 
188
        set_bit(AFS_VNODE_MOUNTPOINT, &vnode->flags);
 
189
        inode->i_flags |= S_AUTOMOUNT | S_NOATIME;
 
190
        unlock_new_inode(inode);
 
191
        _leave(" = %p", inode);
 
192
        return inode;
 
193
}
 
194
 
 
195
/*
 
196
 * inode retrieval
 
197
 */
 
198
struct inode *afs_iget(struct super_block *sb, struct key *key,
 
199
                       struct afs_fid *fid, struct afs_file_status *status,
 
200
                       struct afs_callback *cb)
 
201
{
 
202
        struct afs_iget_data data = { .fid = *fid };
 
203
        struct afs_super_info *as;
 
204
        struct afs_vnode *vnode;
 
205
        struct inode *inode;
 
206
        int ret;
 
207
 
 
208
        _enter(",{%x:%u.%u},,", fid->vid, fid->vnode, fid->unique);
 
209
 
 
210
        as = sb->s_fs_info;
 
211
        data.volume = as->volume;
 
212
 
 
213
        inode = iget5_locked(sb, fid->vnode, afs_iget5_test, afs_iget5_set,
 
214
                             &data);
 
215
        if (!inode) {
 
216
                _leave(" = -ENOMEM");
 
217
                return ERR_PTR(-ENOMEM);
 
218
        }
 
219
 
 
220
        _debug("GOT INODE %p { vl=%x vn=%x, u=%x }",
 
221
               inode, fid->vid, fid->vnode, fid->unique);
 
222
 
 
223
        vnode = AFS_FS_I(inode);
 
224
 
 
225
        /* deal with an existing inode */
 
226
        if (!(inode->i_state & I_NEW)) {
 
227
                _leave(" = %p", inode);
 
228
                return inode;
 
229
        }
 
230
 
 
231
        if (!status) {
 
232
                /* it's a remotely extant inode */
 
233
                set_bit(AFS_VNODE_CB_BROKEN, &vnode->flags);
 
234
                ret = afs_vnode_fetch_status(vnode, NULL, key);
 
235
                if (ret < 0)
 
236
                        goto bad_inode;
 
237
        } else {
 
238
                /* it's an inode we just created */
 
239
                memcpy(&vnode->status, status, sizeof(vnode->status));
 
240
 
 
241
                if (!cb) {
 
242
                        /* it's a symlink we just created (the fileserver
 
243
                         * didn't give us a callback) */
 
244
                        vnode->cb_version = 0;
 
245
                        vnode->cb_expiry = 0;
 
246
                        vnode->cb_type = 0;
 
247
                        vnode->cb_expires = get_seconds();
 
248
                } else {
 
249
                        vnode->cb_version = cb->version;
 
250
                        vnode->cb_expiry = cb->expiry;
 
251
                        vnode->cb_type = cb->type;
 
252
                        vnode->cb_expires = vnode->cb_expiry + get_seconds();
 
253
                }
 
254
        }
 
255
 
 
256
        /* set up caching before mapping the status, as map-status reads the
 
257
         * first page of symlinks to see if they're really mountpoints */
 
258
        inode->i_size = vnode->status.size;
 
259
#ifdef CONFIG_AFS_FSCACHE
 
260
        vnode->cache = fscache_acquire_cookie(vnode->volume->cache,
 
261
                                              &afs_vnode_cache_index_def,
 
262
                                              vnode);
 
263
#endif
 
264
 
 
265
        ret = afs_inode_map_status(vnode, key);
 
266
        if (ret < 0)
 
267
                goto bad_inode;
 
268
 
 
269
        /* success */
 
270
        clear_bit(AFS_VNODE_UNSET, &vnode->flags);
 
271
        inode->i_flags |= S_NOATIME;
 
272
        unlock_new_inode(inode);
 
273
        _leave(" = %p [CB { v=%u t=%u }]", inode, vnode->cb_version, vnode->cb_type);
 
274
        return inode;
 
275
 
 
276
        /* failure */
 
277
bad_inode:
 
278
#ifdef CONFIG_AFS_FSCACHE
 
279
        fscache_relinquish_cookie(vnode->cache, 0);
 
280
        vnode->cache = NULL;
 
281
#endif
 
282
        iget_failed(inode);
 
283
        _leave(" = %d [bad]", ret);
 
284
        return ERR_PTR(ret);
 
285
}
 
286
 
 
287
/*
 
288
 * mark the data attached to an inode as obsolete due to a write on the server
 
289
 * - might also want to ditch all the outstanding writes and dirty pages
 
290
 */
 
291
void afs_zap_data(struct afs_vnode *vnode)
 
292
{
 
293
        _enter("{%x:%u}", vnode->fid.vid, vnode->fid.vnode);
 
294
 
 
295
        /* nuke all the non-dirty pages that aren't locked, mapped or being
 
296
         * written back in a regular file and completely discard the pages in a
 
297
         * directory or symlink */
 
298
        if (S_ISREG(vnode->vfs_inode.i_mode))
 
299
                invalidate_remote_inode(&vnode->vfs_inode);
 
300
        else
 
301
                invalidate_inode_pages2(vnode->vfs_inode.i_mapping);
 
302
}
 
303
 
 
304
/*
 
305
 * validate a vnode/inode
 
306
 * - there are several things we need to check
 
307
 *   - parent dir data changes (rm, rmdir, rename, mkdir, create, link,
 
308
 *     symlink)
 
309
 *   - parent dir metadata changed (security changes)
 
310
 *   - dentry data changed (write, truncate)
 
311
 *   - dentry metadata changed (security changes)
 
312
 */
 
313
int afs_validate(struct afs_vnode *vnode, struct key *key)
 
314
{
 
315
        int ret;
 
316
 
 
317
        _enter("{v={%x:%u} fl=%lx},%x",
 
318
               vnode->fid.vid, vnode->fid.vnode, vnode->flags,
 
319
               key_serial(key));
 
320
 
 
321
        if (vnode->cb_promised &&
 
322
            !test_bit(AFS_VNODE_CB_BROKEN, &vnode->flags) &&
 
323
            !test_bit(AFS_VNODE_MODIFIED, &vnode->flags) &&
 
324
            !test_bit(AFS_VNODE_ZAP_DATA, &vnode->flags)) {
 
325
                if (vnode->cb_expires < get_seconds() + 10) {
 
326
                        _debug("callback expired");
 
327
                        set_bit(AFS_VNODE_CB_BROKEN, &vnode->flags);
 
328
                } else {
 
329
                        goto valid;
 
330
                }
 
331
        }
 
332
 
 
333
        if (test_bit(AFS_VNODE_DELETED, &vnode->flags))
 
334
                goto valid;
 
335
 
 
336
        mutex_lock(&vnode->validate_lock);
 
337
 
 
338
        /* if the promise has expired, we need to check the server again to get
 
339
         * a new promise - note that if the (parent) directory's metadata was
 
340
         * changed then the security may be different and we may no longer have
 
341
         * access */
 
342
        if (!vnode->cb_promised ||
 
343
            test_bit(AFS_VNODE_CB_BROKEN, &vnode->flags)) {
 
344
                _debug("not promised");
 
345
                ret = afs_vnode_fetch_status(vnode, NULL, key);
 
346
                if (ret < 0)
 
347
                        goto error_unlock;
 
348
                _debug("new promise [fl=%lx]", vnode->flags);
 
349
        }
 
350
 
 
351
        if (test_bit(AFS_VNODE_DELETED, &vnode->flags)) {
 
352
                _debug("file already deleted");
 
353
                ret = -ESTALE;
 
354
                goto error_unlock;
 
355
        }
 
356
 
 
357
        /* if the vnode's data version number changed then its contents are
 
358
         * different */
 
359
        if (test_and_clear_bit(AFS_VNODE_ZAP_DATA, &vnode->flags))
 
360
                afs_zap_data(vnode);
 
361
 
 
362
        clear_bit(AFS_VNODE_MODIFIED, &vnode->flags);
 
363
        mutex_unlock(&vnode->validate_lock);
 
364
valid:
 
365
        _leave(" = 0");
 
366
        return 0;
 
367
 
 
368
error_unlock:
 
369
        mutex_unlock(&vnode->validate_lock);
 
370
        _leave(" = %d", ret);
 
371
        return ret;
 
372
}
 
373
 
 
374
/*
 
375
 * read the attributes of an inode
 
376
 */
 
377
int afs_getattr(struct vfsmount *mnt, struct dentry *dentry,
 
378
                      struct kstat *stat)
 
379
{
 
380
        struct inode *inode;
 
381
 
 
382
        inode = dentry->d_inode;
 
383
 
 
384
        _enter("{ ino=%lu v=%u }", inode->i_ino, inode->i_generation);
 
385
 
 
386
        generic_fillattr(inode, stat);
 
387
        return 0;
 
388
}
 
389
 
 
390
/*
 
391
 * discard an AFS inode
 
392
 */
 
393
int afs_drop_inode(struct inode *inode)
 
394
{
 
395
        _enter("");
 
396
 
 
397
        if (test_bit(AFS_VNODE_PSEUDODIR, &AFS_FS_I(inode)->flags))
 
398
                return generic_delete_inode(inode);
 
399
        else
 
400
                return generic_drop_inode(inode);
 
401
}
 
402
 
 
403
/*
 
404
 * clear an AFS inode
 
405
 */
 
406
void afs_evict_inode(struct inode *inode)
 
407
{
 
408
        struct afs_permits *permits;
 
409
        struct afs_vnode *vnode;
 
410
 
 
411
        vnode = AFS_FS_I(inode);
 
412
 
 
413
        _enter("{%x:%u.%d} v=%u x=%u t=%u }",
 
414
               vnode->fid.vid,
 
415
               vnode->fid.vnode,
 
416
               vnode->fid.unique,
 
417
               vnode->cb_version,
 
418
               vnode->cb_expiry,
 
419
               vnode->cb_type);
 
420
 
 
421
        _debug("CLEAR INODE %p", inode);
 
422
 
 
423
        ASSERTCMP(inode->i_ino, ==, vnode->fid.vnode);
 
424
 
 
425
        truncate_inode_pages(&inode->i_data, 0);
 
426
        end_writeback(inode);
 
427
 
 
428
        afs_give_up_callback(vnode);
 
429
 
 
430
        if (vnode->server) {
 
431
                spin_lock(&vnode->server->fs_lock);
 
432
                rb_erase(&vnode->server_rb, &vnode->server->fs_vnodes);
 
433
                spin_unlock(&vnode->server->fs_lock);
 
434
                afs_put_server(vnode->server);
 
435
                vnode->server = NULL;
 
436
        }
 
437
 
 
438
        ASSERT(list_empty(&vnode->writebacks));
 
439
        ASSERT(!vnode->cb_promised);
 
440
 
 
441
#ifdef CONFIG_AFS_FSCACHE
 
442
        fscache_relinquish_cookie(vnode->cache, 0);
 
443
        vnode->cache = NULL;
 
444
#endif
 
445
 
 
446
        mutex_lock(&vnode->permits_lock);
 
447
        permits = vnode->permits;
 
448
        rcu_assign_pointer(vnode->permits, NULL);
 
449
        mutex_unlock(&vnode->permits_lock);
 
450
        if (permits)
 
451
                call_rcu(&permits->rcu, afs_zap_permits);
 
452
 
 
453
        _leave("");
 
454
}
 
455
 
 
456
/*
 
457
 * set the attributes of an inode
 
458
 */
 
459
int afs_setattr(struct dentry *dentry, struct iattr *attr)
 
460
{
 
461
        struct afs_vnode *vnode = AFS_FS_I(dentry->d_inode);
 
462
        struct key *key;
 
463
        int ret;
 
464
 
 
465
        _enter("{%x:%u},{n=%s},%x",
 
466
               vnode->fid.vid, vnode->fid.vnode, dentry->d_name.name,
 
467
               attr->ia_valid);
 
468
 
 
469
        if (!(attr->ia_valid & (ATTR_SIZE | ATTR_MODE | ATTR_UID | ATTR_GID |
 
470
                                ATTR_MTIME))) {
 
471
                _leave(" = 0 [unsupported]");
 
472
                return 0;
 
473
        }
 
474
 
 
475
        /* flush any dirty data outstanding on a regular file */
 
476
        if (S_ISREG(vnode->vfs_inode.i_mode)) {
 
477
                filemap_write_and_wait(vnode->vfs_inode.i_mapping);
 
478
                afs_writeback_all(vnode);
 
479
        }
 
480
 
 
481
        if (attr->ia_valid & ATTR_FILE) {
 
482
                key = attr->ia_file->private_data;
 
483
        } else {
 
484
                key = afs_request_key(vnode->volume->cell);
 
485
                if (IS_ERR(key)) {
 
486
                        ret = PTR_ERR(key);
 
487
                        goto error;
 
488
                }
 
489
        }
 
490
 
 
491
        ret = afs_vnode_setattr(vnode, key, attr);
 
492
        if (!(attr->ia_valid & ATTR_FILE))
 
493
                key_put(key);
 
494
 
 
495
error:
 
496
        _leave(" = %d", ret);
 
497
        return ret;
 
498
}