diff options
Diffstat (limited to 'fs')
-rw-r--r-- | fs/btrfs/inode.c | 21 | ||||
-rw-r--r-- | fs/buffer.c | 7 | ||||
-rw-r--r-- | fs/exec.c | 4 | ||||
-rw-r--r-- | fs/ext3/Kconfig | 32 | ||||
-rw-r--r-- | fs/ext3/super.c | 40 | ||||
-rw-r--r-- | fs/gfs2/sys.c | 20 | ||||
-rw-r--r-- | fs/hugetlbfs/inode.c | 20 | ||||
-rw-r--r-- | fs/libfs.c | 2 | ||||
-rw-r--r-- | fs/nfs/nfs4state.c | 4 | ||||
-rw-r--r-- | fs/nilfs2/super.c | 2 | ||||
-rw-r--r-- | fs/nilfs2/the_nilfs.h | 2 | ||||
-rw-r--r-- | fs/notify/inotify/inotify_fsnotify.c | 13 | ||||
-rw-r--r-- | fs/notify/inotify/inotify_user.c | 9 | ||||
-rw-r--r-- | fs/notify/notification.c | 11 | ||||
-rw-r--r-- | fs/ocfs2/alloc.c | 2 | ||||
-rw-r--r-- | fs/ocfs2/dlm/dlmunlock.c | 4 | ||||
-rw-r--r-- | fs/ocfs2/ocfs2_lockid.h | 1 | ||||
-rw-r--r-- | fs/ocfs2/quota_global.c | 10 | ||||
-rw-r--r-- | fs/ocfs2/super.c | 6 | ||||
-rw-r--r-- | fs/proc/base.c | 19 | ||||
-rw-r--r-- | fs/select.c | 1 | ||||
-rw-r--r-- | fs/xfs/linux-2.6/xfs_sync.c | 13 | ||||
-rw-r--r-- | fs/xfs/linux-2.6/xfs_sync.h | 1 | ||||
-rw-r--r-- | fs/xfs/xfs_iget.c | 113 |
24 files changed, 204 insertions, 153 deletions
diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c index 272b9b2bea86..59cba180fe83 100644 --- a/fs/btrfs/inode.c +++ b/fs/btrfs/inode.c | |||
@@ -3099,8 +3099,12 @@ static void inode_tree_add(struct inode *inode) | |||
3099 | { | 3099 | { |
3100 | struct btrfs_root *root = BTRFS_I(inode)->root; | 3100 | struct btrfs_root *root = BTRFS_I(inode)->root; |
3101 | struct btrfs_inode *entry; | 3101 | struct btrfs_inode *entry; |
3102 | struct rb_node **p = &root->inode_tree.rb_node; | 3102 | struct rb_node **p; |
3103 | struct rb_node *parent = NULL; | 3103 | struct rb_node *parent; |
3104 | |||
3105 | again: | ||
3106 | p = &root->inode_tree.rb_node; | ||
3107 | parent = NULL; | ||
3104 | 3108 | ||
3105 | spin_lock(&root->inode_lock); | 3109 | spin_lock(&root->inode_lock); |
3106 | while (*p) { | 3110 | while (*p) { |
@@ -3108,13 +3112,16 @@ static void inode_tree_add(struct inode *inode) | |||
3108 | entry = rb_entry(parent, struct btrfs_inode, rb_node); | 3112 | entry = rb_entry(parent, struct btrfs_inode, rb_node); |
3109 | 3113 | ||
3110 | if (inode->i_ino < entry->vfs_inode.i_ino) | 3114 | if (inode->i_ino < entry->vfs_inode.i_ino) |
3111 | p = &(*p)->rb_left; | 3115 | p = &parent->rb_left; |
3112 | else if (inode->i_ino > entry->vfs_inode.i_ino) | 3116 | else if (inode->i_ino > entry->vfs_inode.i_ino) |
3113 | p = &(*p)->rb_right; | 3117 | p = &parent->rb_right; |
3114 | else { | 3118 | else { |
3115 | WARN_ON(!(entry->vfs_inode.i_state & | 3119 | WARN_ON(!(entry->vfs_inode.i_state & |
3116 | (I_WILL_FREE | I_FREEING | I_CLEAR))); | 3120 | (I_WILL_FREE | I_FREEING | I_CLEAR))); |
3117 | break; | 3121 | rb_erase(parent, &root->inode_tree); |
3122 | RB_CLEAR_NODE(parent); | ||
3123 | spin_unlock(&root->inode_lock); | ||
3124 | goto again; | ||
3118 | } | 3125 | } |
3119 | } | 3126 | } |
3120 | rb_link_node(&BTRFS_I(inode)->rb_node, parent, p); | 3127 | rb_link_node(&BTRFS_I(inode)->rb_node, parent, p); |
@@ -3126,12 +3133,12 @@ static void inode_tree_del(struct inode *inode) | |||
3126 | { | 3133 | { |
3127 | struct btrfs_root *root = BTRFS_I(inode)->root; | 3134 | struct btrfs_root *root = BTRFS_I(inode)->root; |
3128 | 3135 | ||
3136 | spin_lock(&root->inode_lock); | ||
3129 | if (!RB_EMPTY_NODE(&BTRFS_I(inode)->rb_node)) { | 3137 | if (!RB_EMPTY_NODE(&BTRFS_I(inode)->rb_node)) { |
3130 | spin_lock(&root->inode_lock); | ||
3131 | rb_erase(&BTRFS_I(inode)->rb_node, &root->inode_tree); | 3138 | rb_erase(&BTRFS_I(inode)->rb_node, &root->inode_tree); |
3132 | spin_unlock(&root->inode_lock); | ||
3133 | RB_CLEAR_NODE(&BTRFS_I(inode)->rb_node); | 3139 | RB_CLEAR_NODE(&BTRFS_I(inode)->rb_node); |
3134 | } | 3140 | } |
3141 | spin_unlock(&root->inode_lock); | ||
3135 | } | 3142 | } |
3136 | 3143 | ||
3137 | static noinline void init_btrfs_i(struct inode *inode) | 3144 | static noinline void init_btrfs_i(struct inode *inode) |
diff --git a/fs/buffer.c b/fs/buffer.c index a3ef091a45bd..28f320fac4d4 100644 --- a/fs/buffer.c +++ b/fs/buffer.c | |||
@@ -1165,8 +1165,11 @@ void mark_buffer_dirty(struct buffer_head *bh) | |||
1165 | 1165 | ||
1166 | if (!test_set_buffer_dirty(bh)) { | 1166 | if (!test_set_buffer_dirty(bh)) { |
1167 | struct page *page = bh->b_page; | 1167 | struct page *page = bh->b_page; |
1168 | if (!TestSetPageDirty(page)) | 1168 | if (!TestSetPageDirty(page)) { |
1169 | __set_page_dirty(page, page_mapping(page), 0); | 1169 | struct address_space *mapping = page_mapping(page); |
1170 | if (mapping) | ||
1171 | __set_page_dirty(page, mapping, 0); | ||
1172 | } | ||
1170 | } | 1173 | } |
1171 | } | 1174 | } |
1172 | 1175 | ||
@@ -678,8 +678,8 @@ exit: | |||
678 | } | 678 | } |
679 | EXPORT_SYMBOL(open_exec); | 679 | EXPORT_SYMBOL(open_exec); |
680 | 680 | ||
681 | int kernel_read(struct file *file, unsigned long offset, | 681 | int kernel_read(struct file *file, loff_t offset, |
682 | char *addr, unsigned long count) | 682 | char *addr, unsigned long count) |
683 | { | 683 | { |
684 | mm_segment_t old_fs; | 684 | mm_segment_t old_fs; |
685 | loff_t pos = offset; | 685 | loff_t pos = offset; |
diff --git a/fs/ext3/Kconfig b/fs/ext3/Kconfig index fb3c1a21b135..522b15498f45 100644 --- a/fs/ext3/Kconfig +++ b/fs/ext3/Kconfig | |||
@@ -29,23 +29,25 @@ config EXT3_FS | |||
29 | module will be called ext3. | 29 | module will be called ext3. |
30 | 30 | ||
31 | config EXT3_DEFAULTS_TO_ORDERED | 31 | config EXT3_DEFAULTS_TO_ORDERED |
32 | bool "Default to 'data=ordered' in ext3 (legacy option)" | 32 | bool "Default to 'data=ordered' in ext3" |
33 | depends on EXT3_FS | 33 | depends on EXT3_FS |
34 | help | 34 | help |
35 | If a filesystem does not explicitly specify a data ordering | 35 | The journal mode options for ext3 have different tradeoffs |
36 | mode, and the journal capability allowed it, ext3 used to | 36 | between when data is guaranteed to be on disk and |
37 | historically default to 'data=ordered'. | 37 | performance. The use of "data=writeback" can cause |
38 | 38 | unwritten data to appear in files after an system crash or | |
39 | That was a rather unfortunate choice, because it leads to all | 39 | power failure, which can be a security issue. However, |
40 | kinds of latency problems, and the 'data=writeback' mode is more | 40 | "data=ordered" mode can also result in major performance |
41 | appropriate these days. | 41 | problems, including seconds-long delays before an fsync() |
42 | 42 | call returns. For details, see: | |
43 | You should probably always answer 'n' here, and if you really | 43 | |
44 | want to use 'data=ordered' mode, set it in the filesystem itself | 44 | http://ext4.wiki.kernel.org/index.php/Ext3_data_mode_tradeoffs |
45 | with 'tune2fs -o journal_data_ordered'. | 45 | |
46 | 46 | If you have been historically happy with ext3's performance, | |
47 | But if you really want to enable the legacy default, you can do | 47 | data=ordered mode will be a safe choice and you should |
48 | so by answering 'y' to this question. | 48 | answer 'y' here. If you understand the reliability and data |
49 | privacy issues of data=writeback and are willing to make | ||
50 | that trade off, answer 'n'. | ||
49 | 51 | ||
50 | config EXT3_FS_XATTR | 52 | config EXT3_FS_XATTR |
51 | bool "Ext3 extended attributes" | 53 | bool "Ext3 extended attributes" |
diff --git a/fs/ext3/super.c b/fs/ext3/super.c index 524b349c6299..a8d80a7f1105 100644 --- a/fs/ext3/super.c +++ b/fs/ext3/super.c | |||
@@ -543,6 +543,19 @@ static inline void ext3_show_quota_options(struct seq_file *seq, struct super_bl | |||
543 | #endif | 543 | #endif |
544 | } | 544 | } |
545 | 545 | ||
546 | static char *data_mode_string(unsigned long mode) | ||
547 | { | ||
548 | switch (mode) { | ||
549 | case EXT3_MOUNT_JOURNAL_DATA: | ||
550 | return "journal"; | ||
551 | case EXT3_MOUNT_ORDERED_DATA: | ||
552 | return "ordered"; | ||
553 | case EXT3_MOUNT_WRITEBACK_DATA: | ||
554 | return "writeback"; | ||
555 | } | ||
556 | return "unknown"; | ||
557 | } | ||
558 | |||
546 | /* | 559 | /* |
547 | * Show an option if | 560 | * Show an option if |
548 | * - it's set to a non-default value OR | 561 | * - it's set to a non-default value OR |
@@ -616,13 +629,8 @@ static int ext3_show_options(struct seq_file *seq, struct vfsmount *vfs) | |||
616 | if (test_opt(sb, NOBH)) | 629 | if (test_opt(sb, NOBH)) |
617 | seq_puts(seq, ",nobh"); | 630 | seq_puts(seq, ",nobh"); |
618 | 631 | ||
619 | if (test_opt(sb, DATA_FLAGS) == EXT3_MOUNT_JOURNAL_DATA) | 632 | seq_printf(seq, ",data=%s", data_mode_string(sbi->s_mount_opt & |
620 | seq_puts(seq, ",data=journal"); | 633 | EXT3_MOUNT_DATA_FLAGS)); |
621 | else if (test_opt(sb, DATA_FLAGS) == EXT3_MOUNT_ORDERED_DATA) | ||
622 | seq_puts(seq, ",data=ordered"); | ||
623 | else if (test_opt(sb, DATA_FLAGS) == EXT3_MOUNT_WRITEBACK_DATA) | ||
624 | seq_puts(seq, ",data=writeback"); | ||
625 | |||
626 | if (test_opt(sb, DATA_ERR_ABORT)) | 634 | if (test_opt(sb, DATA_ERR_ABORT)) |
627 | seq_puts(seq, ",data_err=abort"); | 635 | seq_puts(seq, ",data_err=abort"); |
628 | 636 | ||
@@ -1024,12 +1032,18 @@ static int parse_options (char *options, struct super_block *sb, | |||
1024 | datacheck: | 1032 | datacheck: |
1025 | if (is_remount) { | 1033 | if (is_remount) { |
1026 | if ((sbi->s_mount_opt & EXT3_MOUNT_DATA_FLAGS) | 1034 | if ((sbi->s_mount_opt & EXT3_MOUNT_DATA_FLAGS) |
1027 | != data_opt) { | 1035 | == data_opt) |
1028 | printk(KERN_ERR | 1036 | break; |
1029 | "EXT3-fs: cannot change data " | 1037 | printk(KERN_ERR |
1030 | "mode on remount\n"); | 1038 | "EXT3-fs (device %s): Cannot change " |
1031 | return 0; | 1039 | "data mode on remount. The filesystem " |
1032 | } | 1040 | "is mounted in data=%s mode and you " |
1041 | "try to remount it in data=%s mode.\n", | ||
1042 | sb->s_id, | ||
1043 | data_mode_string(sbi->s_mount_opt & | ||
1044 | EXT3_MOUNT_DATA_FLAGS), | ||
1045 | data_mode_string(data_opt)); | ||
1046 | return 0; | ||
1033 | } else { | 1047 | } else { |
1034 | sbi->s_mount_opt &= ~EXT3_MOUNT_DATA_FLAGS; | 1048 | sbi->s_mount_opt &= ~EXT3_MOUNT_DATA_FLAGS; |
1035 | sbi->s_mount_opt |= data_opt; | 1049 | sbi->s_mount_opt |= data_opt; |
diff --git a/fs/gfs2/sys.c b/fs/gfs2/sys.c index 23419dc3027b..a7cbfbd340c7 100644 --- a/fs/gfs2/sys.c +++ b/fs/gfs2/sys.c | |||
@@ -386,16 +386,16 @@ static ssize_t jid_show(struct gfs2_sbd *sdp, char *buf) | |||
386 | #define GDLM_ATTR(_name,_mode,_show,_store) \ | 386 | #define GDLM_ATTR(_name,_mode,_show,_store) \ |
387 | static struct gfs2_attr gdlm_attr_##_name = __ATTR(_name,_mode,_show,_store) | 387 | static struct gfs2_attr gdlm_attr_##_name = __ATTR(_name,_mode,_show,_store) |
388 | 388 | ||
389 | GDLM_ATTR(proto_name, 0444, proto_name_show, NULL); | 389 | GDLM_ATTR(proto_name, 0444, proto_name_show, NULL); |
390 | GDLM_ATTR(block, 0644, block_show, block_store); | 390 | GDLM_ATTR(block, 0644, block_show, block_store); |
391 | GDLM_ATTR(withdraw, 0644, withdraw_show, withdraw_store); | 391 | GDLM_ATTR(withdraw, 0644, withdraw_show, withdraw_store); |
392 | GDLM_ATTR(id, 0444, lkid_show, NULL); | 392 | GDLM_ATTR(id, 0444, lkid_show, NULL); |
393 | GDLM_ATTR(jid, 0444, jid_show, NULL); | 393 | GDLM_ATTR(jid, 0444, jid_show, NULL); |
394 | GDLM_ATTR(first, 0444, lkfirst_show, NULL); | 394 | GDLM_ATTR(first, 0444, lkfirst_show, NULL); |
395 | GDLM_ATTR(first_done, 0444, first_done_show, NULL); | 395 | GDLM_ATTR(first_done, 0444, first_done_show, NULL); |
396 | GDLM_ATTR(recover, 0200, NULL, recover_store); | 396 | GDLM_ATTR(recover, 0600, NULL, recover_store); |
397 | GDLM_ATTR(recover_done, 0444, recover_done_show, NULL); | 397 | GDLM_ATTR(recover_done, 0444, recover_done_show, NULL); |
398 | GDLM_ATTR(recover_status, 0444, recover_status_show, NULL); | 398 | GDLM_ATTR(recover_status, 0444, recover_status_show, NULL); |
399 | 399 | ||
400 | static struct attribute *lock_module_attrs[] = { | 400 | static struct attribute *lock_module_attrs[] = { |
401 | &gdlm_attr_proto_name.attr, | 401 | &gdlm_attr_proto_name.attr, |
diff --git a/fs/hugetlbfs/inode.c b/fs/hugetlbfs/inode.c index 941c8425c10b..cb88dac8ccaa 100644 --- a/fs/hugetlbfs/inode.c +++ b/fs/hugetlbfs/inode.c | |||
@@ -935,26 +935,28 @@ static int can_do_hugetlb_shm(void) | |||
935 | return capable(CAP_IPC_LOCK) || in_group_p(sysctl_hugetlb_shm_group); | 935 | return capable(CAP_IPC_LOCK) || in_group_p(sysctl_hugetlb_shm_group); |
936 | } | 936 | } |
937 | 937 | ||
938 | struct file *hugetlb_file_setup(const char *name, size_t size, int acctflag) | 938 | struct file *hugetlb_file_setup(const char *name, size_t size, int acctflag, |
939 | struct user_struct **user) | ||
939 | { | 940 | { |
940 | int error = -ENOMEM; | 941 | int error = -ENOMEM; |
941 | int unlock_shm = 0; | ||
942 | struct file *file; | 942 | struct file *file; |
943 | struct inode *inode; | 943 | struct inode *inode; |
944 | struct dentry *dentry, *root; | 944 | struct dentry *dentry, *root; |
945 | struct qstr quick_string; | 945 | struct qstr quick_string; |
946 | struct user_struct *user = current_user(); | ||
947 | 946 | ||
947 | *user = NULL; | ||
948 | if (!hugetlbfs_vfsmount) | 948 | if (!hugetlbfs_vfsmount) |
949 | return ERR_PTR(-ENOENT); | 949 | return ERR_PTR(-ENOENT); |
950 | 950 | ||
951 | if (!can_do_hugetlb_shm()) { | 951 | if (!can_do_hugetlb_shm()) { |
952 | if (user_shm_lock(size, user)) { | 952 | *user = current_user(); |
953 | unlock_shm = 1; | 953 | if (user_shm_lock(size, *user)) { |
954 | WARN_ONCE(1, | 954 | WARN_ONCE(1, |
955 | "Using mlock ulimits for SHM_HUGETLB deprecated\n"); | 955 | "Using mlock ulimits for SHM_HUGETLB deprecated\n"); |
956 | } else | 956 | } else { |
957 | *user = NULL; | ||
957 | return ERR_PTR(-EPERM); | 958 | return ERR_PTR(-EPERM); |
959 | } | ||
958 | } | 960 | } |
959 | 961 | ||
960 | root = hugetlbfs_vfsmount->mnt_root; | 962 | root = hugetlbfs_vfsmount->mnt_root; |
@@ -996,8 +998,10 @@ out_inode: | |||
996 | out_dentry: | 998 | out_dentry: |
997 | dput(dentry); | 999 | dput(dentry); |
998 | out_shm_unlock: | 1000 | out_shm_unlock: |
999 | if (unlock_shm) | 1001 | if (*user) { |
1000 | user_shm_unlock(size, user); | 1002 | user_shm_unlock(size, *user); |
1003 | *user = NULL; | ||
1004 | } | ||
1001 | return ERR_PTR(error); | 1005 | return ERR_PTR(error); |
1002 | } | 1006 | } |
1003 | 1007 | ||
diff --git a/fs/libfs.c b/fs/libfs.c index ddfa89948c3f..dcec3d3ea64f 100644 --- a/fs/libfs.c +++ b/fs/libfs.c | |||
@@ -217,7 +217,7 @@ int get_sb_pseudo(struct file_system_type *fs_type, char *name, | |||
217 | return PTR_ERR(s); | 217 | return PTR_ERR(s); |
218 | 218 | ||
219 | s->s_flags = MS_NOUSER; | 219 | s->s_flags = MS_NOUSER; |
220 | s->s_maxbytes = ~0ULL; | 220 | s->s_maxbytes = MAX_LFS_FILESIZE; |
221 | s->s_blocksize = PAGE_SIZE; | 221 | s->s_blocksize = PAGE_SIZE; |
222 | s->s_blocksize_bits = PAGE_SHIFT; | 222 | s->s_blocksize_bits = PAGE_SHIFT; |
223 | s->s_magic = magic; | 223 | s->s_magic = magic; |
diff --git a/fs/nfs/nfs4state.c b/fs/nfs/nfs4state.c index 65ca8c18476f..1434080aefeb 100644 --- a/fs/nfs/nfs4state.c +++ b/fs/nfs/nfs4state.c | |||
@@ -1250,8 +1250,8 @@ static void nfs4_state_manager(struct nfs_client *clp) | |||
1250 | continue; | 1250 | continue; |
1251 | } | 1251 | } |
1252 | /* Initialize or reset the session */ | 1252 | /* Initialize or reset the session */ |
1253 | if (nfs4_has_session(clp) && | 1253 | if (test_and_clear_bit(NFS4CLNT_SESSION_SETUP, &clp->cl_state) |
1254 | test_and_clear_bit(NFS4CLNT_SESSION_SETUP, &clp->cl_state)) { | 1254 | && nfs4_has_session(clp)) { |
1255 | if (clp->cl_cons_state == NFS_CS_SESSION_INITING) | 1255 | if (clp->cl_cons_state == NFS_CS_SESSION_INITING) |
1256 | status = nfs4_initialize_session(clp); | 1256 | status = nfs4_initialize_session(clp); |
1257 | else | 1257 | else |
diff --git a/fs/nilfs2/super.c b/fs/nilfs2/super.c index 8e2ec43b18f4..151964f0de4c 100644 --- a/fs/nilfs2/super.c +++ b/fs/nilfs2/super.c | |||
@@ -416,8 +416,10 @@ int nilfs_attach_checkpoint(struct nilfs_sb_info *sbi, __u64 cno) | |||
416 | if (unlikely(err)) | 416 | if (unlikely(err)) |
417 | goto failed; | 417 | goto failed; |
418 | 418 | ||
419 | down_read(&nilfs->ns_segctor_sem); | ||
419 | err = nilfs_cpfile_get_checkpoint(nilfs->ns_cpfile, cno, 0, &raw_cp, | 420 | err = nilfs_cpfile_get_checkpoint(nilfs->ns_cpfile, cno, 0, &raw_cp, |
420 | &bh_cp); | 421 | &bh_cp); |
422 | up_read(&nilfs->ns_segctor_sem); | ||
421 | if (unlikely(err)) { | 423 | if (unlikely(err)) { |
422 | if (err == -ENOENT || err == -EINVAL) { | 424 | if (err == -ENOENT || err == -EINVAL) { |
423 | printk(KERN_ERR | 425 | printk(KERN_ERR |
diff --git a/fs/nilfs2/the_nilfs.h b/fs/nilfs2/the_nilfs.h index e8adbffc626f..1b9caafb8662 100644 --- a/fs/nilfs2/the_nilfs.h +++ b/fs/nilfs2/the_nilfs.h | |||
@@ -253,7 +253,7 @@ nilfs_detach_writer(struct the_nilfs *nilfs, struct nilfs_sb_info *sbi) | |||
253 | 253 | ||
254 | static inline void nilfs_put_sbinfo(struct nilfs_sb_info *sbi) | 254 | static inline void nilfs_put_sbinfo(struct nilfs_sb_info *sbi) |
255 | { | 255 | { |
256 | if (!atomic_dec_and_test(&sbi->s_count)) | 256 | if (atomic_dec_and_test(&sbi->s_count)) |
257 | kfree(sbi); | 257 | kfree(sbi); |
258 | } | 258 | } |
259 | 259 | ||
diff --git a/fs/notify/inotify/inotify_fsnotify.c b/fs/notify/inotify/inotify_fsnotify.c index 47cd258fd24d..5dcbafe72d71 100644 --- a/fs/notify/inotify/inotify_fsnotify.c +++ b/fs/notify/inotify/inotify_fsnotify.c | |||
@@ -62,13 +62,14 @@ static int inotify_handle_event(struct fsnotify_group *group, struct fsnotify_ev | |||
62 | event_priv->wd = wd; | 62 | event_priv->wd = wd; |
63 | 63 | ||
64 | ret = fsnotify_add_notify_event(group, event, fsn_event_priv); | 64 | ret = fsnotify_add_notify_event(group, event, fsn_event_priv); |
65 | /* EEXIST is not an error */ | 65 | if (ret) { |
66 | if (ret == -EEXIST) | ||
67 | ret = 0; | ||
68 | |||
69 | /* did event_priv get attached? */ | ||
70 | if (list_empty(&fsn_event_priv->event_list)) | ||
71 | inotify_free_event_priv(fsn_event_priv); | 66 | inotify_free_event_priv(fsn_event_priv); |
67 | /* EEXIST says we tail matched, EOVERFLOW isn't something | ||
68 | * to report up the stack. */ | ||
69 | if ((ret == -EEXIST) || | ||
70 | (ret == -EOVERFLOW)) | ||
71 | ret = 0; | ||
72 | } | ||
72 | 73 | ||
73 | /* | 74 | /* |
74 | * If we hold the entry until after the event is on the queue | 75 | * If we hold the entry until after the event is on the queue |
diff --git a/fs/notify/inotify/inotify_user.c b/fs/notify/inotify/inotify_user.c index f30d9bbc2e1b..dc32ed8323ba 100644 --- a/fs/notify/inotify/inotify_user.c +++ b/fs/notify/inotify/inotify_user.c | |||
@@ -386,6 +386,7 @@ void inotify_ignored_and_remove_idr(struct fsnotify_mark_entry *entry, | |||
386 | struct fsnotify_event *ignored_event; | 386 | struct fsnotify_event *ignored_event; |
387 | struct inotify_event_private_data *event_priv; | 387 | struct inotify_event_private_data *event_priv; |
388 | struct fsnotify_event_private_data *fsn_event_priv; | 388 | struct fsnotify_event_private_data *fsn_event_priv; |
389 | int ret; | ||
389 | 390 | ||
390 | ignored_event = fsnotify_create_event(NULL, FS_IN_IGNORED, NULL, | 391 | ignored_event = fsnotify_create_event(NULL, FS_IN_IGNORED, NULL, |
391 | FSNOTIFY_EVENT_NONE, NULL, 0, | 392 | FSNOTIFY_EVENT_NONE, NULL, 0, |
@@ -404,10 +405,8 @@ void inotify_ignored_and_remove_idr(struct fsnotify_mark_entry *entry, | |||
404 | fsn_event_priv->group = group; | 405 | fsn_event_priv->group = group; |
405 | event_priv->wd = ientry->wd; | 406 | event_priv->wd = ientry->wd; |
406 | 407 | ||
407 | fsnotify_add_notify_event(group, ignored_event, fsn_event_priv); | 408 | ret = fsnotify_add_notify_event(group, ignored_event, fsn_event_priv); |
408 | 409 | if (ret) | |
409 | /* did the private data get added? */ | ||
410 | if (list_empty(&fsn_event_priv->event_list)) | ||
411 | inotify_free_event_priv(fsn_event_priv); | 410 | inotify_free_event_priv(fsn_event_priv); |
412 | 411 | ||
413 | skip_send_ignore: | 412 | skip_send_ignore: |
@@ -568,7 +567,7 @@ static struct fsnotify_group *inotify_new_group(struct user_struct *user, unsign | |||
568 | 567 | ||
569 | spin_lock_init(&group->inotify_data.idr_lock); | 568 | spin_lock_init(&group->inotify_data.idr_lock); |
570 | idr_init(&group->inotify_data.idr); | 569 | idr_init(&group->inotify_data.idr); |
571 | group->inotify_data.last_wd = 0; | 570 | group->inotify_data.last_wd = 1; |
572 | group->inotify_data.user = user; | 571 | group->inotify_data.user = user; |
573 | group->inotify_data.fa = NULL; | 572 | group->inotify_data.fa = NULL; |
574 | 573 | ||
diff --git a/fs/notify/notification.c b/fs/notify/notification.c index 521368574e97..3816d5750dd5 100644 --- a/fs/notify/notification.c +++ b/fs/notify/notification.c | |||
@@ -153,6 +153,10 @@ static bool event_compare(struct fsnotify_event *old, struct fsnotify_event *new | |||
153 | return true; | 153 | return true; |
154 | break; | 154 | break; |
155 | case (FSNOTIFY_EVENT_NONE): | 155 | case (FSNOTIFY_EVENT_NONE): |
156 | if (old->mask & FS_Q_OVERFLOW) | ||
157 | return true; | ||
158 | else if (old->mask & FS_IN_IGNORED) | ||
159 | return false; | ||
156 | return false; | 160 | return false; |
157 | }; | 161 | }; |
158 | } | 162 | } |
@@ -171,9 +175,7 @@ int fsnotify_add_notify_event(struct fsnotify_group *group, struct fsnotify_even | |||
171 | struct list_head *list = &group->notification_list; | 175 | struct list_head *list = &group->notification_list; |
172 | struct fsnotify_event_holder *last_holder; | 176 | struct fsnotify_event_holder *last_holder; |
173 | struct fsnotify_event *last_event; | 177 | struct fsnotify_event *last_event; |
174 | 178 | int ret = 0; | |
175 | /* easy to tell if priv was attached to the event */ | ||
176 | INIT_LIST_HEAD(&priv->event_list); | ||
177 | 179 | ||
178 | /* | 180 | /* |
179 | * There is one fsnotify_event_holder embedded inside each fsnotify_event. | 181 | * There is one fsnotify_event_holder embedded inside each fsnotify_event. |
@@ -194,6 +196,7 @@ alloc_holder: | |||
194 | 196 | ||
195 | if (group->q_len >= group->max_events) { | 197 | if (group->q_len >= group->max_events) { |
196 | event = &q_overflow_event; | 198 | event = &q_overflow_event; |
199 | ret = -EOVERFLOW; | ||
197 | /* sorry, no private data on the overflow event */ | 200 | /* sorry, no private data on the overflow event */ |
198 | priv = NULL; | 201 | priv = NULL; |
199 | } | 202 | } |
@@ -235,7 +238,7 @@ alloc_holder: | |||
235 | mutex_unlock(&group->notification_mutex); | 238 | mutex_unlock(&group->notification_mutex); |
236 | 239 | ||
237 | wake_up(&group->notification_waitq); | 240 | wake_up(&group->notification_waitq); |
238 | return 0; | 241 | return ret; |
239 | } | 242 | } |
240 | 243 | ||
241 | /* | 244 | /* |
diff --git a/fs/ocfs2/alloc.c b/fs/ocfs2/alloc.c index f9a3e8942669..ab513ddaeff2 100644 --- a/fs/ocfs2/alloc.c +++ b/fs/ocfs2/alloc.c | |||
@@ -6851,7 +6851,7 @@ static int ocfs2_do_truncate(struct ocfs2_super *osb, | |||
6851 | } | 6851 | } |
6852 | status = 0; | 6852 | status = 0; |
6853 | bail: | 6853 | bail: |
6854 | 6854 | brelse(last_eb_bh); | |
6855 | mlog_exit(status); | 6855 | mlog_exit(status); |
6856 | return status; | 6856 | return status; |
6857 | } | 6857 | } |
diff --git a/fs/ocfs2/dlm/dlmunlock.c b/fs/ocfs2/dlm/dlmunlock.c index fcf879ed6930..756f5b0998e0 100644 --- a/fs/ocfs2/dlm/dlmunlock.c +++ b/fs/ocfs2/dlm/dlmunlock.c | |||
@@ -122,7 +122,7 @@ static enum dlm_status dlmunlock_common(struct dlm_ctxt *dlm, | |||
122 | * that still has AST's pending... */ | 122 | * that still has AST's pending... */ |
123 | in_use = !list_empty(&lock->ast_list); | 123 | in_use = !list_empty(&lock->ast_list); |
124 | spin_unlock(&dlm->ast_lock); | 124 | spin_unlock(&dlm->ast_lock); |
125 | if (in_use) { | 125 | if (in_use && !(flags & LKM_CANCEL)) { |
126 | mlog(ML_ERROR, "lockres %.*s: Someone is calling dlmunlock " | 126 | mlog(ML_ERROR, "lockres %.*s: Someone is calling dlmunlock " |
127 | "while waiting for an ast!", res->lockname.len, | 127 | "while waiting for an ast!", res->lockname.len, |
128 | res->lockname.name); | 128 | res->lockname.name); |
@@ -131,7 +131,7 @@ static enum dlm_status dlmunlock_common(struct dlm_ctxt *dlm, | |||
131 | 131 | ||
132 | spin_lock(&res->spinlock); | 132 | spin_lock(&res->spinlock); |
133 | if (res->state & DLM_LOCK_RES_IN_PROGRESS) { | 133 | if (res->state & DLM_LOCK_RES_IN_PROGRESS) { |
134 | if (master_node) { | 134 | if (master_node && !(flags & LKM_CANCEL)) { |
135 | mlog(ML_ERROR, "lockres in progress!\n"); | 135 | mlog(ML_ERROR, "lockres in progress!\n"); |
136 | spin_unlock(&res->spinlock); | 136 | spin_unlock(&res->spinlock); |
137 | return DLM_FORWARD; | 137 | return DLM_FORWARD; |
diff --git a/fs/ocfs2/ocfs2_lockid.h b/fs/ocfs2/ocfs2_lockid.h index fcdba091af3d..c212cf5a2bdf 100644 --- a/fs/ocfs2/ocfs2_lockid.h +++ b/fs/ocfs2/ocfs2_lockid.h | |||
@@ -108,6 +108,7 @@ static char *ocfs2_lock_type_strings[] = { | |||
108 | [OCFS2_LOCK_TYPE_OPEN] = "Open", | 108 | [OCFS2_LOCK_TYPE_OPEN] = "Open", |
109 | [OCFS2_LOCK_TYPE_FLOCK] = "Flock", | 109 | [OCFS2_LOCK_TYPE_FLOCK] = "Flock", |
110 | [OCFS2_LOCK_TYPE_QINFO] = "Quota", | 110 | [OCFS2_LOCK_TYPE_QINFO] = "Quota", |
111 | [OCFS2_LOCK_TYPE_NFS_SYNC] = "NFSSync", | ||
111 | [OCFS2_LOCK_TYPE_ORPHAN_SCAN] = "OrphanScan", | 112 | [OCFS2_LOCK_TYPE_ORPHAN_SCAN] = "OrphanScan", |
112 | }; | 113 | }; |
113 | 114 | ||
diff --git a/fs/ocfs2/quota_global.c b/fs/ocfs2/quota_global.c index bf7742d0ee3b..44f2a5e1d042 100644 --- a/fs/ocfs2/quota_global.c +++ b/fs/ocfs2/quota_global.c | |||
@@ -23,6 +23,7 @@ | |||
23 | #include "sysfile.h" | 23 | #include "sysfile.h" |
24 | #include "dlmglue.h" | 24 | #include "dlmglue.h" |
25 | #include "uptodate.h" | 25 | #include "uptodate.h" |
26 | #include "super.h" | ||
26 | #include "quota.h" | 27 | #include "quota.h" |
27 | 28 | ||
28 | static struct workqueue_struct *ocfs2_quota_wq = NULL; | 29 | static struct workqueue_struct *ocfs2_quota_wq = NULL; |
@@ -114,6 +115,15 @@ int ocfs2_read_quota_block(struct inode *inode, u64 v_block, | |||
114 | int rc = 0; | 115 | int rc = 0; |
115 | struct buffer_head *tmp = *bh; | 116 | struct buffer_head *tmp = *bh; |
116 | 117 | ||
118 | if (i_size_read(inode) >> inode->i_sb->s_blocksize_bits <= v_block) { | ||
119 | ocfs2_error(inode->i_sb, | ||
120 | "Quota file %llu is probably corrupted! Requested " | ||
121 | "to read block %Lu but file has size only %Lu\n", | ||
122 | (unsigned long long)OCFS2_I(inode)->ip_blkno, | ||
123 | (unsigned long long)v_block, | ||
124 | (unsigned long long)i_size_read(inode)); | ||
125 | return -EIO; | ||
126 | } | ||
117 | rc = ocfs2_read_virt_blocks(inode, v_block, 1, &tmp, 0, | 127 | rc = ocfs2_read_virt_blocks(inode, v_block, 1, &tmp, 0, |
118 | ocfs2_validate_quota_block); | 128 | ocfs2_validate_quota_block); |
119 | if (rc) | 129 | if (rc) |
diff --git a/fs/ocfs2/super.c b/fs/ocfs2/super.c index b0ee0fdf799a..a3f8871d21fd 100644 --- a/fs/ocfs2/super.c +++ b/fs/ocfs2/super.c | |||
@@ -1218,13 +1218,17 @@ static void ocfs2_kill_sb(struct super_block *sb) | |||
1218 | { | 1218 | { |
1219 | struct ocfs2_super *osb = OCFS2_SB(sb); | 1219 | struct ocfs2_super *osb = OCFS2_SB(sb); |
1220 | 1220 | ||
1221 | /* Failed mount? */ | ||
1222 | if (!osb || atomic_read(&osb->vol_state) == VOLUME_DISABLED) | ||
1223 | goto out; | ||
1224 | |||
1221 | /* Prevent further queueing of inode drop events */ | 1225 | /* Prevent further queueing of inode drop events */ |
1222 | spin_lock(&dentry_list_lock); | 1226 | spin_lock(&dentry_list_lock); |
1223 | ocfs2_set_osb_flag(osb, OCFS2_OSB_DROP_DENTRY_LOCK_IMMED); | 1227 | ocfs2_set_osb_flag(osb, OCFS2_OSB_DROP_DENTRY_LOCK_IMMED); |
1224 | spin_unlock(&dentry_list_lock); | 1228 | spin_unlock(&dentry_list_lock); |
1225 | /* Wait for work to finish and/or remove it */ | 1229 | /* Wait for work to finish and/or remove it */ |
1226 | cancel_work_sync(&osb->dentry_lock_work); | 1230 | cancel_work_sync(&osb->dentry_lock_work); |
1227 | 1231 | out: | |
1228 | kill_block_super(sb); | 1232 | kill_block_super(sb); |
1229 | } | 1233 | } |
1230 | 1234 | ||
diff --git a/fs/proc/base.c b/fs/proc/base.c index 175db258942f..6f742f6658a9 100644 --- a/fs/proc/base.c +++ b/fs/proc/base.c | |||
@@ -1003,12 +1003,7 @@ static ssize_t oom_adjust_read(struct file *file, char __user *buf, | |||
1003 | 1003 | ||
1004 | if (!task) | 1004 | if (!task) |
1005 | return -ESRCH; | 1005 | return -ESRCH; |
1006 | task_lock(task); | 1006 | oom_adjust = task->oomkilladj; |
1007 | if (task->mm) | ||
1008 | oom_adjust = task->mm->oom_adj; | ||
1009 | else | ||
1010 | oom_adjust = OOM_DISABLE; | ||
1011 | task_unlock(task); | ||
1012 | put_task_struct(task); | 1007 | put_task_struct(task); |
1013 | 1008 | ||
1014 | len = snprintf(buffer, sizeof(buffer), "%i\n", oom_adjust); | 1009 | len = snprintf(buffer, sizeof(buffer), "%i\n", oom_adjust); |
@@ -1037,19 +1032,11 @@ static ssize_t oom_adjust_write(struct file *file, const char __user *buf, | |||
1037 | task = get_proc_task(file->f_path.dentry->d_inode); | 1032 | task = get_proc_task(file->f_path.dentry->d_inode); |
1038 | if (!task) | 1033 | if (!task) |
1039 | return -ESRCH; | 1034 | return -ESRCH; |
1040 | task_lock(task); | 1035 | if (oom_adjust < task->oomkilladj && !capable(CAP_SYS_RESOURCE)) { |
1041 | if (!task->mm) { | ||
1042 | task_unlock(task); | ||
1043 | put_task_struct(task); | ||
1044 | return -EINVAL; | ||
1045 | } | ||
1046 | if (oom_adjust < task->mm->oom_adj && !capable(CAP_SYS_RESOURCE)) { | ||
1047 | task_unlock(task); | ||
1048 | put_task_struct(task); | 1036 | put_task_struct(task); |
1049 | return -EACCES; | 1037 | return -EACCES; |
1050 | } | 1038 | } |
1051 | task->mm->oom_adj = oom_adjust; | 1039 | task->oomkilladj = oom_adjust; |
1052 | task_unlock(task); | ||
1053 | put_task_struct(task); | 1040 | put_task_struct(task); |
1054 | if (end - buffer == 0) | 1041 | if (end - buffer == 0) |
1055 | return -EIO; | 1042 | return -EIO; |
diff --git a/fs/select.c b/fs/select.c index d870237e42c7..8084834e123e 100644 --- a/fs/select.c +++ b/fs/select.c | |||
@@ -110,6 +110,7 @@ void poll_initwait(struct poll_wqueues *pwq) | |||
110 | { | 110 | { |
111 | init_poll_funcptr(&pwq->pt, __pollwait); | 111 | init_poll_funcptr(&pwq->pt, __pollwait); |
112 | pwq->polling_task = current; | 112 | pwq->polling_task = current; |
113 | pwq->triggered = 0; | ||
113 | pwq->error = 0; | 114 | pwq->error = 0; |
114 | pwq->table = NULL; | 115 | pwq->table = NULL; |
115 | pwq->inline_index = 0; | 116 | pwq->inline_index = 0; |
diff --git a/fs/xfs/linux-2.6/xfs_sync.c b/fs/xfs/linux-2.6/xfs_sync.c index b619d6b8ca43..98ef624d9baf 100644 --- a/fs/xfs/linux-2.6/xfs_sync.c +++ b/fs/xfs/linux-2.6/xfs_sync.c | |||
@@ -708,6 +708,16 @@ xfs_reclaim_inode( | |||
708 | return 0; | 708 | return 0; |
709 | } | 709 | } |
710 | 710 | ||
711 | void | ||
712 | __xfs_inode_set_reclaim_tag( | ||
713 | struct xfs_perag *pag, | ||
714 | struct xfs_inode *ip) | ||
715 | { | ||
716 | radix_tree_tag_set(&pag->pag_ici_root, | ||
717 | XFS_INO_TO_AGINO(ip->i_mount, ip->i_ino), | ||
718 | XFS_ICI_RECLAIM_TAG); | ||
719 | } | ||
720 | |||
711 | /* | 721 | /* |
712 | * We set the inode flag atomically with the radix tree tag. | 722 | * We set the inode flag atomically with the radix tree tag. |
713 | * Once we get tag lookups on the radix tree, this inode flag | 723 | * Once we get tag lookups on the radix tree, this inode flag |
@@ -722,8 +732,7 @@ xfs_inode_set_reclaim_tag( | |||
722 | 732 | ||
723 | read_lock(&pag->pag_ici_lock); | 733 | read_lock(&pag->pag_ici_lock); |
724 | spin_lock(&ip->i_flags_lock); | 734 | spin_lock(&ip->i_flags_lock); |
725 | radix_tree_tag_set(&pag->pag_ici_root, | 735 | __xfs_inode_set_reclaim_tag(pag, ip); |
726 | XFS_INO_TO_AGINO(mp, ip->i_ino), XFS_ICI_RECLAIM_TAG); | ||
727 | __xfs_iflags_set(ip, XFS_IRECLAIMABLE); | 736 | __xfs_iflags_set(ip, XFS_IRECLAIMABLE); |
728 | spin_unlock(&ip->i_flags_lock); | 737 | spin_unlock(&ip->i_flags_lock); |
729 | read_unlock(&pag->pag_ici_lock); | 738 | read_unlock(&pag->pag_ici_lock); |
diff --git a/fs/xfs/linux-2.6/xfs_sync.h b/fs/xfs/linux-2.6/xfs_sync.h index 2a10301c99c7..59120602588a 100644 --- a/fs/xfs/linux-2.6/xfs_sync.h +++ b/fs/xfs/linux-2.6/xfs_sync.h | |||
@@ -48,6 +48,7 @@ int xfs_reclaim_inode(struct xfs_inode *ip, int locked, int sync_mode); | |||
48 | int xfs_reclaim_inodes(struct xfs_mount *mp, int mode); | 48 | int xfs_reclaim_inodes(struct xfs_mount *mp, int mode); |
49 | 49 | ||
50 | void xfs_inode_set_reclaim_tag(struct xfs_inode *ip); | 50 | void xfs_inode_set_reclaim_tag(struct xfs_inode *ip); |
51 | void __xfs_inode_set_reclaim_tag(struct xfs_perag *pag, struct xfs_inode *ip); | ||
51 | void xfs_inode_clear_reclaim_tag(struct xfs_inode *ip); | 52 | void xfs_inode_clear_reclaim_tag(struct xfs_inode *ip); |
52 | void __xfs_inode_clear_reclaim_tag(struct xfs_mount *mp, struct xfs_perag *pag, | 53 | void __xfs_inode_clear_reclaim_tag(struct xfs_mount *mp, struct xfs_perag *pag, |
53 | struct xfs_inode *ip); | 54 | struct xfs_inode *ip); |
diff --git a/fs/xfs/xfs_iget.c b/fs/xfs/xfs_iget.c index 34ec86923f7e..ecbf8b4d2e2e 100644 --- a/fs/xfs/xfs_iget.c +++ b/fs/xfs/xfs_iget.c | |||
@@ -191,80 +191,82 @@ xfs_iget_cache_hit( | |||
191 | int flags, | 191 | int flags, |
192 | int lock_flags) __releases(pag->pag_ici_lock) | 192 | int lock_flags) __releases(pag->pag_ici_lock) |
193 | { | 193 | { |
194 | struct inode *inode = VFS_I(ip); | ||
194 | struct xfs_mount *mp = ip->i_mount; | 195 | struct xfs_mount *mp = ip->i_mount; |
195 | int error = EAGAIN; | 196 | int error; |
197 | |||
198 | spin_lock(&ip->i_flags_lock); | ||
196 | 199 | ||
197 | /* | 200 | /* |
198 | * If INEW is set this inode is being set up | 201 | * If we are racing with another cache hit that is currently |
199 | * If IRECLAIM is set this inode is being torn down | 202 | * instantiating this inode or currently recycling it out of |
200 | * Pause and try again. | 203 | * reclaimabe state, wait for the initialisation to complete |
204 | * before continuing. | ||
205 | * | ||
206 | * XXX(hch): eventually we should do something equivalent to | ||
207 | * wait_on_inode to wait for these flags to be cleared | ||
208 | * instead of polling for it. | ||
201 | */ | 209 | */ |
202 | if (xfs_iflags_test(ip, (XFS_INEW|XFS_IRECLAIM))) { | 210 | if (ip->i_flags & (XFS_INEW|XFS_IRECLAIM)) { |
203 | XFS_STATS_INC(xs_ig_frecycle); | 211 | XFS_STATS_INC(xs_ig_frecycle); |
212 | error = EAGAIN; | ||
204 | goto out_error; | 213 | goto out_error; |
205 | } | 214 | } |
206 | 215 | ||
207 | /* If IRECLAIMABLE is set, we've torn down the vfs inode part */ | 216 | /* |
208 | if (xfs_iflags_test(ip, XFS_IRECLAIMABLE)) { | 217 | * If lookup is racing with unlink return an error immediately. |
209 | 218 | */ | |
210 | /* | 219 | if (ip->i_d.di_mode == 0 && !(flags & XFS_IGET_CREATE)) { |
211 | * If lookup is racing with unlink, then we should return an | 220 | error = ENOENT; |
212 | * error immediately so we don't remove it from the reclaim | 221 | goto out_error; |
213 | * list and potentially leak the inode. | 222 | } |
214 | */ | ||
215 | if ((ip->i_d.di_mode == 0) && !(flags & XFS_IGET_CREATE)) { | ||
216 | error = ENOENT; | ||
217 | goto out_error; | ||
218 | } | ||
219 | 223 | ||
224 | /* | ||
225 | * If IRECLAIMABLE is set, we've torn down the VFS inode already. | ||
226 | * Need to carefully get it back into useable state. | ||
227 | */ | ||
228 | if (ip->i_flags & XFS_IRECLAIMABLE) { | ||
220 | xfs_itrace_exit_tag(ip, "xfs_iget.alloc"); | 229 | xfs_itrace_exit_tag(ip, "xfs_iget.alloc"); |
221 | 230 | ||
222 | /* | 231 | /* |
223 | * We need to re-initialise the VFS inode as it has been | 232 | * We need to set XFS_INEW atomically with clearing the |
224 | * 'freed' by the VFS. Do this here so we can deal with | 233 | * reclaimable tag so that we do have an indicator of the |
225 | * errors cleanly, then tag it so it can be set up correctly | 234 | * inode still being initialized. |
226 | * later. | ||
227 | */ | 235 | */ |
228 | if (inode_init_always(mp->m_super, VFS_I(ip))) { | 236 | ip->i_flags |= XFS_INEW; |
229 | error = ENOMEM; | 237 | ip->i_flags &= ~XFS_IRECLAIMABLE; |
230 | goto out_error; | 238 | __xfs_inode_clear_reclaim_tag(mp, pag, ip); |
231 | } | ||
232 | 239 | ||
233 | /* | 240 | spin_unlock(&ip->i_flags_lock); |
234 | * We must set the XFS_INEW flag before clearing the | 241 | read_unlock(&pag->pag_ici_lock); |
235 | * XFS_IRECLAIMABLE flag so that if a racing lookup does | ||
236 | * not find the XFS_IRECLAIMABLE above but has the igrab() | ||
237 | * below succeed we can safely check XFS_INEW to detect | ||
238 | * that this inode is still being initialised. | ||
239 | */ | ||
240 | xfs_iflags_set(ip, XFS_INEW); | ||
241 | xfs_iflags_clear(ip, XFS_IRECLAIMABLE); | ||
242 | 242 | ||
243 | /* clear the radix tree reclaim flag as well. */ | 243 | error = -inode_init_always(mp->m_super, inode); |
244 | __xfs_inode_clear_reclaim_tag(mp, pag, ip); | 244 | if (error) { |
245 | } else if (!igrab(VFS_I(ip))) { | 245 | /* |
246 | * Re-initializing the inode failed, and we are in deep | ||
247 | * trouble. Try to re-add it to the reclaim list. | ||
248 | */ | ||
249 | read_lock(&pag->pag_ici_lock); | ||
250 | spin_lock(&ip->i_flags_lock); | ||
251 | |||
252 | ip->i_flags &= ~XFS_INEW; | ||
253 | ip->i_flags |= XFS_IRECLAIMABLE; | ||
254 | __xfs_inode_set_reclaim_tag(pag, ip); | ||
255 | goto out_error; | ||
256 | } | ||
257 | inode->i_state = I_LOCK|I_NEW; | ||
258 | } else { | ||
246 | /* If the VFS inode is being torn down, pause and try again. */ | 259 | /* If the VFS inode is being torn down, pause and try again. */ |
247 | XFS_STATS_INC(xs_ig_frecycle); | 260 | if (!igrab(inode)) { |
248 | goto out_error; | 261 | error = EAGAIN; |
249 | } else if (xfs_iflags_test(ip, XFS_INEW)) { | 262 | goto out_error; |
250 | /* | 263 | } |
251 | * We are racing with another cache hit that is | ||
252 | * currently recycling this inode out of the XFS_IRECLAIMABLE | ||
253 | * state. Wait for the initialisation to complete before | ||
254 | * continuing. | ||
255 | */ | ||
256 | wait_on_inode(VFS_I(ip)); | ||
257 | } | ||
258 | 264 | ||
259 | if (ip->i_d.di_mode == 0 && !(flags & XFS_IGET_CREATE)) { | 265 | /* We've got a live one. */ |
260 | error = ENOENT; | 266 | spin_unlock(&ip->i_flags_lock); |
261 | iput(VFS_I(ip)); | 267 | read_unlock(&pag->pag_ici_lock); |
262 | goto out_error; | ||
263 | } | 268 | } |
264 | 269 | ||
265 | /* We've got a live one. */ | ||
266 | read_unlock(&pag->pag_ici_lock); | ||
267 | |||
268 | if (lock_flags != 0) | 270 | if (lock_flags != 0) |
269 | xfs_ilock(ip, lock_flags); | 271 | xfs_ilock(ip, lock_flags); |
270 | 272 | ||
@@ -274,6 +276,7 @@ xfs_iget_cache_hit( | |||
274 | return 0; | 276 | return 0; |
275 | 277 | ||
276 | out_error: | 278 | out_error: |
279 | spin_unlock(&ip->i_flags_lock); | ||
277 | read_unlock(&pag->pag_ici_lock); | 280 | read_unlock(&pag->pag_ici_lock); |
278 | return error; | 281 | return error; |
279 | } | 282 | } |