diff options
-rw-r--r-- | fs/cifs/TODO | 2 | ||||
-rw-r--r-- | fs/cifs/cifs_fs_sb.h | 6 | ||||
-rw-r--r-- | fs/cifs/cifsfs.c | 5 | ||||
-rw-r--r-- | fs/cifs/cifsglob.h | 3 | ||||
-rw-r--r-- | fs/cifs/cifsproto.h | 1 | ||||
-rw-r--r-- | fs/cifs/connect.c | 195 | ||||
-rw-r--r-- | fs/cifs/file.c | 72 | ||||
-rw-r--r-- | fs/cifs/ioctl.c | 4 | ||||
-rw-r--r-- | fs/cifs/misc.c | 25 |
9 files changed, 152 insertions, 161 deletions
diff --git a/fs/cifs/TODO b/fs/cifs/TODO index 5aff46c61e52..355abcdcda98 100644 --- a/fs/cifs/TODO +++ b/fs/cifs/TODO | |||
@@ -81,7 +81,7 @@ u) DOS attrs - returned as pseudo-xattr in Samba format (check VFAT and NTFS for | |||
81 | 81 | ||
82 | v) mount check for unmatched uids | 82 | v) mount check for unmatched uids |
83 | 83 | ||
84 | w) Add support for new vfs entry points for setlease and fallocate | 84 | w) Add support for new vfs entry point for fallocate |
85 | 85 | ||
86 | x) Fix Samba 3 server to handle Linux kernel aio so dbench with lots of | 86 | x) Fix Samba 3 server to handle Linux kernel aio so dbench with lots of |
87 | processes can proceed better in parallel (on the server) | 87 | processes can proceed better in parallel (on the server) |
diff --git a/fs/cifs/cifs_fs_sb.h b/fs/cifs/cifs_fs_sb.h index 525ba59a4105..e9a393c9c2ca 100644 --- a/fs/cifs/cifs_fs_sb.h +++ b/fs/cifs/cifs_fs_sb.h | |||
@@ -15,7 +15,7 @@ | |||
15 | * the GNU Lesser General Public License for more details. | 15 | * the GNU Lesser General Public License for more details. |
16 | * | 16 | * |
17 | */ | 17 | */ |
18 | #include <linux/radix-tree.h> | 18 | #include <linux/rbtree.h> |
19 | 19 | ||
20 | #ifndef _CIFS_FS_SB_H | 20 | #ifndef _CIFS_FS_SB_H |
21 | #define _CIFS_FS_SB_H | 21 | #define _CIFS_FS_SB_H |
@@ -42,9 +42,9 @@ | |||
42 | #define CIFS_MOUNT_MULTIUSER 0x20000 /* multiuser mount */ | 42 | #define CIFS_MOUNT_MULTIUSER 0x20000 /* multiuser mount */ |
43 | 43 | ||
44 | struct cifs_sb_info { | 44 | struct cifs_sb_info { |
45 | struct radix_tree_root tlink_tree; | 45 | struct rb_root tlink_tree; |
46 | #define CIFS_TLINK_MASTER_TAG 0 /* is "master" (mount) tcon */ | ||
47 | spinlock_t tlink_tree_lock; | 46 | spinlock_t tlink_tree_lock; |
47 | struct tcon_link *master_tlink; | ||
48 | struct nls_table *local_nls; | 48 | struct nls_table *local_nls; |
49 | unsigned int rsize; | 49 | unsigned int rsize; |
50 | unsigned int wsize; | 50 | unsigned int wsize; |
diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c index 75c4eaa79588..9c3789762ab7 100644 --- a/fs/cifs/cifsfs.c +++ b/fs/cifs/cifsfs.c | |||
@@ -116,7 +116,7 @@ cifs_read_super(struct super_block *sb, void *data, | |||
116 | return -ENOMEM; | 116 | return -ENOMEM; |
117 | 117 | ||
118 | spin_lock_init(&cifs_sb->tlink_tree_lock); | 118 | spin_lock_init(&cifs_sb->tlink_tree_lock); |
119 | INIT_RADIX_TREE(&cifs_sb->tlink_tree, GFP_KERNEL); | 119 | cifs_sb->tlink_tree = RB_ROOT; |
120 | 120 | ||
121 | rc = bdi_setup_and_register(&cifs_sb->bdi, "cifs", BDI_CAP_MAP_COPY); | 121 | rc = bdi_setup_and_register(&cifs_sb->bdi, "cifs", BDI_CAP_MAP_COPY); |
122 | if (rc) { | 122 | if (rc) { |
@@ -321,8 +321,7 @@ cifs_alloc_inode(struct super_block *sb) | |||
321 | /* Until the file is open and we have gotten oplock | 321 | /* Until the file is open and we have gotten oplock |
322 | info back from the server, can not assume caching of | 322 | info back from the server, can not assume caching of |
323 | file data or metadata */ | 323 | file data or metadata */ |
324 | cifs_inode->clientCanCacheRead = false; | 324 | cifs_set_oplock_level(cifs_inode, 0); |
325 | cifs_inode->clientCanCacheAll = false; | ||
326 | cifs_inode->delete_pending = false; | 325 | cifs_inode->delete_pending = false; |
327 | cifs_inode->invalid_mapping = false; | 326 | cifs_inode->invalid_mapping = false; |
328 | cifs_inode->vfs_inode.i_blkbits = 14; /* 2**14 = CIFS_MAX_MSGSIZE */ | 327 | cifs_inode->vfs_inode.i_blkbits = 14; /* 2**14 = CIFS_MAX_MSGSIZE */ |
diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h index f259e4d7612d..b577bf0a1bb3 100644 --- a/fs/cifs/cifsglob.h +++ b/fs/cifs/cifsglob.h | |||
@@ -336,7 +336,8 @@ struct cifsTconInfo { | |||
336 | * "get" on the container. | 336 | * "get" on the container. |
337 | */ | 337 | */ |
338 | struct tcon_link { | 338 | struct tcon_link { |
339 | unsigned long tl_index; | 339 | struct rb_node tl_rbnode; |
340 | uid_t tl_uid; | ||
340 | unsigned long tl_flags; | 341 | unsigned long tl_flags; |
341 | #define TCON_LINK_MASTER 0 | 342 | #define TCON_LINK_MASTER 0 |
342 | #define TCON_LINK_PENDING 1 | 343 | #define TCON_LINK_PENDING 1 |
diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h index edb6d90efdf2..7ed69b6b5fe6 100644 --- a/fs/cifs/cifsproto.h +++ b/fs/cifs/cifsproto.h | |||
@@ -104,6 +104,7 @@ extern struct timespec cifs_NTtimeToUnix(__le64 utc_nanoseconds_since_1601); | |||
104 | extern u64 cifs_UnixTimeToNT(struct timespec); | 104 | extern u64 cifs_UnixTimeToNT(struct timespec); |
105 | extern struct timespec cnvrtDosUnixTm(__le16 le_date, __le16 le_time, | 105 | extern struct timespec cnvrtDosUnixTm(__le16 le_date, __le16 le_time, |
106 | int offset); | 106 | int offset); |
107 | extern void cifs_set_oplock_level(struct cifsInodeInfo *cinode, __u32 oplock); | ||
107 | 108 | ||
108 | extern struct cifsFileInfo *cifs_new_fileinfo(__u16 fileHandle, | 109 | extern struct cifsFileInfo *cifs_new_fileinfo(__u16 fileHandle, |
109 | struct file *file, struct tcon_link *tlink, | 110 | struct file *file, struct tcon_link *tlink, |
diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c index 9eb327defa1d..251a17c03545 100644 --- a/fs/cifs/connect.c +++ b/fs/cifs/connect.c | |||
@@ -116,6 +116,7 @@ struct smb_vol { | |||
116 | 116 | ||
117 | static int ipv4_connect(struct TCP_Server_Info *server); | 117 | static int ipv4_connect(struct TCP_Server_Info *server); |
118 | static int ipv6_connect(struct TCP_Server_Info *server); | 118 | static int ipv6_connect(struct TCP_Server_Info *server); |
119 | static void tlink_rb_insert(struct rb_root *root, struct tcon_link *new_tlink); | ||
119 | static void cifs_prune_tlinks(struct work_struct *work); | 120 | static void cifs_prune_tlinks(struct work_struct *work); |
120 | 121 | ||
121 | /* | 122 | /* |
@@ -2900,24 +2901,16 @@ remote_path_check: | |||
2900 | goto mount_fail_check; | 2901 | goto mount_fail_check; |
2901 | } | 2902 | } |
2902 | 2903 | ||
2903 | tlink->tl_index = pSesInfo->linux_uid; | 2904 | tlink->tl_uid = pSesInfo->linux_uid; |
2904 | tlink->tl_tcon = tcon; | 2905 | tlink->tl_tcon = tcon; |
2905 | tlink->tl_time = jiffies; | 2906 | tlink->tl_time = jiffies; |
2906 | set_bit(TCON_LINK_MASTER, &tlink->tl_flags); | 2907 | set_bit(TCON_LINK_MASTER, &tlink->tl_flags); |
2907 | set_bit(TCON_LINK_IN_TREE, &tlink->tl_flags); | 2908 | set_bit(TCON_LINK_IN_TREE, &tlink->tl_flags); |
2908 | 2909 | ||
2909 | rc = radix_tree_preload(GFP_KERNEL); | 2910 | cifs_sb->master_tlink = tlink; |
2910 | if (rc == -ENOMEM) { | ||
2911 | kfree(tlink); | ||
2912 | goto mount_fail_check; | ||
2913 | } | ||
2914 | |||
2915 | spin_lock(&cifs_sb->tlink_tree_lock); | 2911 | spin_lock(&cifs_sb->tlink_tree_lock); |
2916 | radix_tree_insert(&cifs_sb->tlink_tree, pSesInfo->linux_uid, tlink); | 2912 | tlink_rb_insert(&cifs_sb->tlink_tree, tlink); |
2917 | radix_tree_tag_set(&cifs_sb->tlink_tree, pSesInfo->linux_uid, | ||
2918 | CIFS_TLINK_MASTER_TAG); | ||
2919 | spin_unlock(&cifs_sb->tlink_tree_lock); | 2913 | spin_unlock(&cifs_sb->tlink_tree_lock); |
2920 | radix_tree_preload_end(); | ||
2921 | 2914 | ||
2922 | queue_delayed_work(system_nrt_wq, &cifs_sb->prune_tlinks, | 2915 | queue_delayed_work(system_nrt_wq, &cifs_sb->prune_tlinks, |
2923 | TLINK_IDLE_EXPIRE); | 2916 | TLINK_IDLE_EXPIRE); |
@@ -3107,32 +3100,25 @@ CIFSTCon(unsigned int xid, struct cifsSesInfo *ses, | |||
3107 | int | 3100 | int |
3108 | cifs_umount(struct super_block *sb, struct cifs_sb_info *cifs_sb) | 3101 | cifs_umount(struct super_block *sb, struct cifs_sb_info *cifs_sb) |
3109 | { | 3102 | { |
3110 | int i, ret; | 3103 | struct rb_root *root = &cifs_sb->tlink_tree; |
3104 | struct rb_node *node; | ||
3105 | struct tcon_link *tlink; | ||
3111 | char *tmp; | 3106 | char *tmp; |
3112 | struct tcon_link *tlink[8]; | ||
3113 | unsigned long index = 0; | ||
3114 | 3107 | ||
3115 | cancel_delayed_work_sync(&cifs_sb->prune_tlinks); | 3108 | cancel_delayed_work_sync(&cifs_sb->prune_tlinks); |
3116 | 3109 | ||
3117 | do { | 3110 | spin_lock(&cifs_sb->tlink_tree_lock); |
3118 | spin_lock(&cifs_sb->tlink_tree_lock); | 3111 | while ((node = rb_first(root))) { |
3119 | ret = radix_tree_gang_lookup(&cifs_sb->tlink_tree, | 3112 | tlink = rb_entry(node, struct tcon_link, tl_rbnode); |
3120 | (void **)tlink, index, | 3113 | cifs_get_tlink(tlink); |
3121 | ARRAY_SIZE(tlink)); | 3114 | clear_bit(TCON_LINK_IN_TREE, &tlink->tl_flags); |
3122 | /* increment index for next pass */ | 3115 | rb_erase(node, root); |
3123 | if (ret > 0) | ||
3124 | index = tlink[ret - 1]->tl_index + 1; | ||
3125 | for (i = 0; i < ret; i++) { | ||
3126 | cifs_get_tlink(tlink[i]); | ||
3127 | clear_bit(TCON_LINK_IN_TREE, &tlink[i]->tl_flags); | ||
3128 | radix_tree_delete(&cifs_sb->tlink_tree, | ||
3129 | tlink[i]->tl_index); | ||
3130 | } | ||
3131 | spin_unlock(&cifs_sb->tlink_tree_lock); | ||
3132 | 3116 | ||
3133 | for (i = 0; i < ret; i++) | 3117 | spin_unlock(&cifs_sb->tlink_tree_lock); |
3134 | cifs_put_tlink(tlink[i]); | 3118 | cifs_put_tlink(tlink); |
3135 | } while (ret != 0); | 3119 | spin_lock(&cifs_sb->tlink_tree_lock); |
3120 | } | ||
3121 | spin_unlock(&cifs_sb->tlink_tree_lock); | ||
3136 | 3122 | ||
3137 | tmp = cifs_sb->prepath; | 3123 | tmp = cifs_sb->prepath; |
3138 | cifs_sb->prepathlen = 0; | 3124 | cifs_sb->prepathlen = 0; |
@@ -3271,22 +3257,10 @@ out: | |||
3271 | return tcon; | 3257 | return tcon; |
3272 | } | 3258 | } |
3273 | 3259 | ||
3274 | static struct tcon_link * | 3260 | static inline struct tcon_link * |
3275 | cifs_sb_master_tlink(struct cifs_sb_info *cifs_sb) | 3261 | cifs_sb_master_tlink(struct cifs_sb_info *cifs_sb) |
3276 | { | 3262 | { |
3277 | struct tcon_link *tlink; | 3263 | return cifs_sb->master_tlink; |
3278 | unsigned int ret; | ||
3279 | |||
3280 | spin_lock(&cifs_sb->tlink_tree_lock); | ||
3281 | ret = radix_tree_gang_lookup_tag(&cifs_sb->tlink_tree, (void **)&tlink, | ||
3282 | 0, 1, CIFS_TLINK_MASTER_TAG); | ||
3283 | spin_unlock(&cifs_sb->tlink_tree_lock); | ||
3284 | |||
3285 | /* the master tcon should always be present */ | ||
3286 | if (ret == 0) | ||
3287 | BUG(); | ||
3288 | |||
3289 | return tlink; | ||
3290 | } | 3264 | } |
3291 | 3265 | ||
3292 | struct cifsTconInfo * | 3266 | struct cifsTconInfo * |
@@ -3302,6 +3276,47 @@ cifs_sb_tcon_pending_wait(void *unused) | |||
3302 | return signal_pending(current) ? -ERESTARTSYS : 0; | 3276 | return signal_pending(current) ? -ERESTARTSYS : 0; |
3303 | } | 3277 | } |
3304 | 3278 | ||
3279 | /* find and return a tlink with given uid */ | ||
3280 | static struct tcon_link * | ||
3281 | tlink_rb_search(struct rb_root *root, uid_t uid) | ||
3282 | { | ||
3283 | struct rb_node *node = root->rb_node; | ||
3284 | struct tcon_link *tlink; | ||
3285 | |||
3286 | while (node) { | ||
3287 | tlink = rb_entry(node, struct tcon_link, tl_rbnode); | ||
3288 | |||
3289 | if (tlink->tl_uid > uid) | ||
3290 | node = node->rb_left; | ||
3291 | else if (tlink->tl_uid < uid) | ||
3292 | node = node->rb_right; | ||
3293 | else | ||
3294 | return tlink; | ||
3295 | } | ||
3296 | return NULL; | ||
3297 | } | ||
3298 | |||
3299 | /* insert a tcon_link into the tree */ | ||
3300 | static void | ||
3301 | tlink_rb_insert(struct rb_root *root, struct tcon_link *new_tlink) | ||
3302 | { | ||
3303 | struct rb_node **new = &(root->rb_node), *parent = NULL; | ||
3304 | struct tcon_link *tlink; | ||
3305 | |||
3306 | while (*new) { | ||
3307 | tlink = rb_entry(*new, struct tcon_link, tl_rbnode); | ||
3308 | parent = *new; | ||
3309 | |||
3310 | if (tlink->tl_uid > new_tlink->tl_uid) | ||
3311 | new = &((*new)->rb_left); | ||
3312 | else | ||
3313 | new = &((*new)->rb_right); | ||
3314 | } | ||
3315 | |||
3316 | rb_link_node(&new_tlink->tl_rbnode, parent, new); | ||
3317 | rb_insert_color(&new_tlink->tl_rbnode, root); | ||
3318 | } | ||
3319 | |||
3305 | /* | 3320 | /* |
3306 | * Find or construct an appropriate tcon given a cifs_sb and the fsuid of the | 3321 | * Find or construct an appropriate tcon given a cifs_sb and the fsuid of the |
3307 | * current task. | 3322 | * current task. |
@@ -3309,7 +3324,7 @@ cifs_sb_tcon_pending_wait(void *unused) | |||
3309 | * If the superblock doesn't refer to a multiuser mount, then just return | 3324 | * If the superblock doesn't refer to a multiuser mount, then just return |
3310 | * the master tcon for the mount. | 3325 | * the master tcon for the mount. |
3311 | * | 3326 | * |
3312 | * First, search the radix tree for an existing tcon for this fsuid. If one | 3327 | * First, search the rbtree for an existing tcon for this fsuid. If one |
3313 | * exists, then check to see if it's pending construction. If it is then wait | 3328 | * exists, then check to see if it's pending construction. If it is then wait |
3314 | * for construction to complete. Once it's no longer pending, check to see if | 3329 | * for construction to complete. Once it's no longer pending, check to see if |
3315 | * it failed and either return an error or retry construction, depending on | 3330 | * it failed and either return an error or retry construction, depending on |
@@ -3322,14 +3337,14 @@ struct tcon_link * | |||
3322 | cifs_sb_tlink(struct cifs_sb_info *cifs_sb) | 3337 | cifs_sb_tlink(struct cifs_sb_info *cifs_sb) |
3323 | { | 3338 | { |
3324 | int ret; | 3339 | int ret; |
3325 | unsigned long fsuid = (unsigned long) current_fsuid(); | 3340 | uid_t fsuid = current_fsuid(); |
3326 | struct tcon_link *tlink, *newtlink; | 3341 | struct tcon_link *tlink, *newtlink; |
3327 | 3342 | ||
3328 | if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MULTIUSER)) | 3343 | if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MULTIUSER)) |
3329 | return cifs_get_tlink(cifs_sb_master_tlink(cifs_sb)); | 3344 | return cifs_get_tlink(cifs_sb_master_tlink(cifs_sb)); |
3330 | 3345 | ||
3331 | spin_lock(&cifs_sb->tlink_tree_lock); | 3346 | spin_lock(&cifs_sb->tlink_tree_lock); |
3332 | tlink = radix_tree_lookup(&cifs_sb->tlink_tree, fsuid); | 3347 | tlink = tlink_rb_search(&cifs_sb->tlink_tree, fsuid); |
3333 | if (tlink) | 3348 | if (tlink) |
3334 | cifs_get_tlink(tlink); | 3349 | cifs_get_tlink(tlink); |
3335 | spin_unlock(&cifs_sb->tlink_tree_lock); | 3350 | spin_unlock(&cifs_sb->tlink_tree_lock); |
@@ -3338,36 +3353,24 @@ cifs_sb_tlink(struct cifs_sb_info *cifs_sb) | |||
3338 | newtlink = kzalloc(sizeof(*tlink), GFP_KERNEL); | 3353 | newtlink = kzalloc(sizeof(*tlink), GFP_KERNEL); |
3339 | if (newtlink == NULL) | 3354 | if (newtlink == NULL) |
3340 | return ERR_PTR(-ENOMEM); | 3355 | return ERR_PTR(-ENOMEM); |
3341 | newtlink->tl_index = fsuid; | 3356 | newtlink->tl_uid = fsuid; |
3342 | newtlink->tl_tcon = ERR_PTR(-EACCES); | 3357 | newtlink->tl_tcon = ERR_PTR(-EACCES); |
3343 | set_bit(TCON_LINK_PENDING, &newtlink->tl_flags); | 3358 | set_bit(TCON_LINK_PENDING, &newtlink->tl_flags); |
3344 | set_bit(TCON_LINK_IN_TREE, &newtlink->tl_flags); | 3359 | set_bit(TCON_LINK_IN_TREE, &newtlink->tl_flags); |
3345 | cifs_get_tlink(newtlink); | 3360 | cifs_get_tlink(newtlink); |
3346 | 3361 | ||
3347 | ret = radix_tree_preload(GFP_KERNEL); | ||
3348 | if (ret != 0) { | ||
3349 | kfree(newtlink); | ||
3350 | return ERR_PTR(ret); | ||
3351 | } | ||
3352 | |||
3353 | spin_lock(&cifs_sb->tlink_tree_lock); | 3362 | spin_lock(&cifs_sb->tlink_tree_lock); |
3354 | /* was one inserted after previous search? */ | 3363 | /* was one inserted after previous search? */ |
3355 | tlink = radix_tree_lookup(&cifs_sb->tlink_tree, fsuid); | 3364 | tlink = tlink_rb_search(&cifs_sb->tlink_tree, fsuid); |
3356 | if (tlink) { | 3365 | if (tlink) { |
3357 | cifs_get_tlink(tlink); | 3366 | cifs_get_tlink(tlink); |
3358 | spin_unlock(&cifs_sb->tlink_tree_lock); | 3367 | spin_unlock(&cifs_sb->tlink_tree_lock); |
3359 | radix_tree_preload_end(); | ||
3360 | kfree(newtlink); | 3368 | kfree(newtlink); |
3361 | goto wait_for_construction; | 3369 | goto wait_for_construction; |
3362 | } | 3370 | } |
3363 | ret = radix_tree_insert(&cifs_sb->tlink_tree, fsuid, newtlink); | ||
3364 | spin_unlock(&cifs_sb->tlink_tree_lock); | ||
3365 | radix_tree_preload_end(); | ||
3366 | if (ret) { | ||
3367 | kfree(newtlink); | ||
3368 | return ERR_PTR(ret); | ||
3369 | } | ||
3370 | tlink = newtlink; | 3371 | tlink = newtlink; |
3372 | tlink_rb_insert(&cifs_sb->tlink_tree, tlink); | ||
3373 | spin_unlock(&cifs_sb->tlink_tree_lock); | ||
3371 | } else { | 3374 | } else { |
3372 | wait_for_construction: | 3375 | wait_for_construction: |
3373 | ret = wait_on_bit(&tlink->tl_flags, TCON_LINK_PENDING, | 3376 | ret = wait_on_bit(&tlink->tl_flags, TCON_LINK_PENDING, |
@@ -3413,39 +3416,39 @@ cifs_prune_tlinks(struct work_struct *work) | |||
3413 | { | 3416 | { |
3414 | struct cifs_sb_info *cifs_sb = container_of(work, struct cifs_sb_info, | 3417 | struct cifs_sb_info *cifs_sb = container_of(work, struct cifs_sb_info, |
3415 | prune_tlinks.work); | 3418 | prune_tlinks.work); |
3416 | struct tcon_link *tlink[8]; | 3419 | struct rb_root *root = &cifs_sb->tlink_tree; |
3417 | unsigned long now = jiffies; | 3420 | struct rb_node *node = rb_first(root); |
3418 | unsigned long index = 0; | 3421 | struct rb_node *tmp; |
3419 | int i, ret; | 3422 | struct tcon_link *tlink; |
3420 | 3423 | ||
3421 | do { | 3424 | /* |
3422 | spin_lock(&cifs_sb->tlink_tree_lock); | 3425 | * Because we drop the spinlock in the loop in order to put the tlink |
3423 | ret = radix_tree_gang_lookup(&cifs_sb->tlink_tree, | 3426 | * it's not guarded against removal of links from the tree. The only |
3424 | (void **)tlink, index, | 3427 | * places that remove entries from the tree are this function and |
3425 | ARRAY_SIZE(tlink)); | 3428 | * umounts. Because this function is non-reentrant and is canceled |
3426 | /* increment index for next pass */ | 3429 | * before umount can proceed, this is safe. |
3427 | if (ret > 0) | 3430 | */ |
3428 | index = tlink[ret - 1]->tl_index + 1; | 3431 | spin_lock(&cifs_sb->tlink_tree_lock); |
3429 | for (i = 0; i < ret; i++) { | 3432 | node = rb_first(root); |
3430 | if (test_bit(TCON_LINK_MASTER, &tlink[i]->tl_flags) || | 3433 | while (node != NULL) { |
3431 | atomic_read(&tlink[i]->tl_count) != 0 || | 3434 | tmp = node; |
3432 | time_after(tlink[i]->tl_time + TLINK_IDLE_EXPIRE, | 3435 | node = rb_next(tmp); |
3433 | now)) { | 3436 | tlink = rb_entry(tmp, struct tcon_link, tl_rbnode); |
3434 | tlink[i] = NULL; | 3437 | |
3435 | continue; | 3438 | if (test_bit(TCON_LINK_MASTER, &tlink->tl_flags) || |
3436 | } | 3439 | atomic_read(&tlink->tl_count) != 0 || |
3437 | cifs_get_tlink(tlink[i]); | 3440 | time_after(tlink->tl_time + TLINK_IDLE_EXPIRE, jiffies)) |
3438 | clear_bit(TCON_LINK_IN_TREE, &tlink[i]->tl_flags); | 3441 | continue; |
3439 | radix_tree_delete(&cifs_sb->tlink_tree, | ||
3440 | tlink[i]->tl_index); | ||
3441 | } | ||
3442 | spin_unlock(&cifs_sb->tlink_tree_lock); | ||
3443 | 3442 | ||
3444 | for (i = 0; i < ret; i++) { | 3443 | cifs_get_tlink(tlink); |
3445 | if (tlink[i] != NULL) | 3444 | clear_bit(TCON_LINK_IN_TREE, &tlink->tl_flags); |
3446 | cifs_put_tlink(tlink[i]); | 3445 | rb_erase(tmp, root); |
3447 | } | 3446 | |
3448 | } while (ret != 0); | 3447 | spin_unlock(&cifs_sb->tlink_tree_lock); |
3448 | cifs_put_tlink(tlink); | ||
3449 | spin_lock(&cifs_sb->tlink_tree_lock); | ||
3450 | } | ||
3451 | spin_unlock(&cifs_sb->tlink_tree_lock); | ||
3449 | 3452 | ||
3450 | queue_delayed_work(system_nrt_wq, &cifs_sb->prune_tlinks, | 3453 | queue_delayed_work(system_nrt_wq, &cifs_sb->prune_tlinks, |
3451 | TLINK_IDLE_EXPIRE); | 3454 | TLINK_IDLE_EXPIRE); |
diff --git a/fs/cifs/file.c b/fs/cifs/file.c index ae82159cf7fa..06c3e83fa387 100644 --- a/fs/cifs/file.c +++ b/fs/cifs/file.c | |||
@@ -146,12 +146,7 @@ client_can_cache: | |||
146 | rc = cifs_get_inode_info(&inode, full_path, buf, inode->i_sb, | 146 | rc = cifs_get_inode_info(&inode, full_path, buf, inode->i_sb, |
147 | xid, NULL); | 147 | xid, NULL); |
148 | 148 | ||
149 | if ((oplock & 0xF) == OPLOCK_EXCLUSIVE) { | 149 | cifs_set_oplock_level(pCifsInode, oplock); |
150 | pCifsInode->clientCanCacheAll = true; | ||
151 | pCifsInode->clientCanCacheRead = true; | ||
152 | cFYI(1, "Exclusive Oplock granted on inode %p", inode); | ||
153 | } else if ((oplock & 0xF) == OPLOCK_READ) | ||
154 | pCifsInode->clientCanCacheRead = true; | ||
155 | 150 | ||
156 | return rc; | 151 | return rc; |
157 | } | 152 | } |
@@ -253,12 +248,7 @@ cifs_new_fileinfo(__u16 fileHandle, struct file *file, | |||
253 | list_add_tail(&pCifsFile->flist, &pCifsInode->openFileList); | 248 | list_add_tail(&pCifsFile->flist, &pCifsInode->openFileList); |
254 | spin_unlock(&cifs_file_list_lock); | 249 | spin_unlock(&cifs_file_list_lock); |
255 | 250 | ||
256 | if ((oplock & 0xF) == OPLOCK_EXCLUSIVE) { | 251 | cifs_set_oplock_level(pCifsInode, oplock); |
257 | pCifsInode->clientCanCacheAll = true; | ||
258 | pCifsInode->clientCanCacheRead = true; | ||
259 | cFYI(1, "Exclusive Oplock inode %p", inode); | ||
260 | } else if ((oplock & 0xF) == OPLOCK_READ) | ||
261 | pCifsInode->clientCanCacheRead = true; | ||
262 | 252 | ||
263 | file->private_data = pCifsFile; | 253 | file->private_data = pCifsFile; |
264 | return pCifsFile; | 254 | return pCifsFile; |
@@ -271,8 +261,9 @@ cifs_new_fileinfo(__u16 fileHandle, struct file *file, | |||
271 | */ | 261 | */ |
272 | void cifsFileInfo_put(struct cifsFileInfo *cifs_file) | 262 | void cifsFileInfo_put(struct cifsFileInfo *cifs_file) |
273 | { | 263 | { |
264 | struct inode *inode = cifs_file->dentry->d_inode; | ||
274 | struct cifsTconInfo *tcon = tlink_tcon(cifs_file->tlink); | 265 | struct cifsTconInfo *tcon = tlink_tcon(cifs_file->tlink); |
275 | struct cifsInodeInfo *cifsi = CIFS_I(cifs_file->dentry->d_inode); | 266 | struct cifsInodeInfo *cifsi = CIFS_I(inode); |
276 | struct cifsLockInfo *li, *tmp; | 267 | struct cifsLockInfo *li, *tmp; |
277 | 268 | ||
278 | spin_lock(&cifs_file_list_lock); | 269 | spin_lock(&cifs_file_list_lock); |
@@ -288,8 +279,7 @@ void cifsFileInfo_put(struct cifsFileInfo *cifs_file) | |||
288 | if (list_empty(&cifsi->openFileList)) { | 279 | if (list_empty(&cifsi->openFileList)) { |
289 | cFYI(1, "closing last open instance for inode %p", | 280 | cFYI(1, "closing last open instance for inode %p", |
290 | cifs_file->dentry->d_inode); | 281 | cifs_file->dentry->d_inode); |
291 | cifsi->clientCanCacheRead = false; | 282 | cifs_set_oplock_level(cifsi, 0); |
292 | cifsi->clientCanCacheAll = false; | ||
293 | } | 283 | } |
294 | spin_unlock(&cifs_file_list_lock); | 284 | spin_unlock(&cifs_file_list_lock); |
295 | 285 | ||
@@ -607,8 +597,6 @@ reopen_success: | |||
607 | rc = filemap_write_and_wait(inode->i_mapping); | 597 | rc = filemap_write_and_wait(inode->i_mapping); |
608 | mapping_set_error(inode->i_mapping, rc); | 598 | mapping_set_error(inode->i_mapping, rc); |
609 | 599 | ||
610 | pCifsInode->clientCanCacheAll = false; | ||
611 | pCifsInode->clientCanCacheRead = false; | ||
612 | if (tcon->unix_ext) | 600 | if (tcon->unix_ext) |
613 | rc = cifs_get_inode_info_unix(&inode, | 601 | rc = cifs_get_inode_info_unix(&inode, |
614 | full_path, inode->i_sb, xid); | 602 | full_path, inode->i_sb, xid); |
@@ -622,18 +610,9 @@ reopen_success: | |||
622 | invalidate the current end of file on the server | 610 | invalidate the current end of file on the server |
623 | we can not go to the server to get the new inod | 611 | we can not go to the server to get the new inod |
624 | info */ | 612 | info */ |
625 | if ((oplock & 0xF) == OPLOCK_EXCLUSIVE) { | 613 | |
626 | pCifsInode->clientCanCacheAll = true; | 614 | cifs_set_oplock_level(pCifsInode, oplock); |
627 | pCifsInode->clientCanCacheRead = true; | 615 | |
628 | cFYI(1, "Exclusive Oplock granted on inode %p", | ||
629 | pCifsFile->dentry->d_inode); | ||
630 | } else if ((oplock & 0xF) == OPLOCK_READ) { | ||
631 | pCifsInode->clientCanCacheRead = true; | ||
632 | pCifsInode->clientCanCacheAll = false; | ||
633 | } else { | ||
634 | pCifsInode->clientCanCacheRead = false; | ||
635 | pCifsInode->clientCanCacheAll = false; | ||
636 | } | ||
637 | cifs_relock_file(pCifsFile); | 616 | cifs_relock_file(pCifsFile); |
638 | 617 | ||
639 | reopen_error_exit: | 618 | reopen_error_exit: |
@@ -775,12 +754,6 @@ int cifs_lock(struct file *file, int cmd, struct file_lock *pfLock) | |||
775 | 754 | ||
776 | cifs_sb = CIFS_SB(file->f_path.dentry->d_sb); | 755 | cifs_sb = CIFS_SB(file->f_path.dentry->d_sb); |
777 | tcon = tlink_tcon(((struct cifsFileInfo *)file->private_data)->tlink); | 756 | tcon = tlink_tcon(((struct cifsFileInfo *)file->private_data)->tlink); |
778 | |||
779 | if (file->private_data == NULL) { | ||
780 | rc = -EBADF; | ||
781 | FreeXid(xid); | ||
782 | return rc; | ||
783 | } | ||
784 | netfid = ((struct cifsFileInfo *)file->private_data)->netfid; | 757 | netfid = ((struct cifsFileInfo *)file->private_data)->netfid; |
785 | 758 | ||
786 | if ((tcon->ses->capabilities & CAP_UNIX) && | 759 | if ((tcon->ses->capabilities & CAP_UNIX) && |
@@ -956,6 +929,7 @@ cifs_update_eof(struct cifsInodeInfo *cifsi, loff_t offset, | |||
956 | ssize_t cifs_user_write(struct file *file, const char __user *write_data, | 929 | ssize_t cifs_user_write(struct file *file, const char __user *write_data, |
957 | size_t write_size, loff_t *poffset) | 930 | size_t write_size, loff_t *poffset) |
958 | { | 931 | { |
932 | struct inode *inode = file->f_path.dentry->d_inode; | ||
959 | int rc = 0; | 933 | int rc = 0; |
960 | unsigned int bytes_written = 0; | 934 | unsigned int bytes_written = 0; |
961 | unsigned int total_written; | 935 | unsigned int total_written; |
@@ -963,7 +937,7 @@ ssize_t cifs_user_write(struct file *file, const char __user *write_data, | |||
963 | struct cifsTconInfo *pTcon; | 937 | struct cifsTconInfo *pTcon; |
964 | int xid, long_op; | 938 | int xid, long_op; |
965 | struct cifsFileInfo *open_file; | 939 | struct cifsFileInfo *open_file; |
966 | struct cifsInodeInfo *cifsi = CIFS_I(file->f_path.dentry->d_inode); | 940 | struct cifsInodeInfo *cifsi = CIFS_I(inode); |
967 | 941 | ||
968 | cifs_sb = CIFS_SB(file->f_path.dentry->d_sb); | 942 | cifs_sb = CIFS_SB(file->f_path.dentry->d_sb); |
969 | 943 | ||
@@ -1029,21 +1003,17 @@ ssize_t cifs_user_write(struct file *file, const char __user *write_data, | |||
1029 | 1003 | ||
1030 | cifs_stats_bytes_written(pTcon, total_written); | 1004 | cifs_stats_bytes_written(pTcon, total_written); |
1031 | 1005 | ||
1032 | /* since the write may have blocked check these pointers again */ | ||
1033 | if ((file->f_path.dentry) && (file->f_path.dentry->d_inode)) { | ||
1034 | struct inode *inode = file->f_path.dentry->d_inode; | ||
1035 | /* Do not update local mtime - server will set its actual value on write | 1006 | /* Do not update local mtime - server will set its actual value on write |
1036 | * inode->i_ctime = inode->i_mtime = | 1007 | * inode->i_ctime = inode->i_mtime = |
1037 | * current_fs_time(inode->i_sb);*/ | 1008 | * current_fs_time(inode->i_sb);*/ |
1038 | if (total_written > 0) { | 1009 | if (total_written > 0) { |
1039 | spin_lock(&inode->i_lock); | 1010 | spin_lock(&inode->i_lock); |
1040 | if (*poffset > file->f_path.dentry->d_inode->i_size) | 1011 | if (*poffset > inode->i_size) |
1041 | i_size_write(file->f_path.dentry->d_inode, | 1012 | i_size_write(inode, *poffset); |
1042 | *poffset); | 1013 | spin_unlock(&inode->i_lock); |
1043 | spin_unlock(&inode->i_lock); | ||
1044 | } | ||
1045 | mark_inode_dirty_sync(file->f_path.dentry->d_inode); | ||
1046 | } | 1014 | } |
1015 | mark_inode_dirty_sync(inode); | ||
1016 | |||
1047 | FreeXid(xid); | 1017 | FreeXid(xid); |
1048 | return total_written; | 1018 | return total_written; |
1049 | } | 1019 | } |
@@ -1178,7 +1148,7 @@ struct cifsFileInfo *find_writable_file(struct cifsInodeInfo *cifs_inode, | |||
1178 | bool fsuid_only) | 1148 | bool fsuid_only) |
1179 | { | 1149 | { |
1180 | struct cifsFileInfo *open_file; | 1150 | struct cifsFileInfo *open_file; |
1181 | struct cifs_sb_info *cifs_sb = CIFS_SB(cifs_inode->vfs_inode.i_sb); | 1151 | struct cifs_sb_info *cifs_sb; |
1182 | bool any_available = false; | 1152 | bool any_available = false; |
1183 | int rc; | 1153 | int rc; |
1184 | 1154 | ||
@@ -1192,6 +1162,8 @@ struct cifsFileInfo *find_writable_file(struct cifsInodeInfo *cifs_inode, | |||
1192 | return NULL; | 1162 | return NULL; |
1193 | } | 1163 | } |
1194 | 1164 | ||
1165 | cifs_sb = CIFS_SB(cifs_inode->vfs_inode.i_sb); | ||
1166 | |||
1195 | /* only filter by fsuid on multiuser mounts */ | 1167 | /* only filter by fsuid on multiuser mounts */ |
1196 | if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MULTIUSER)) | 1168 | if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MULTIUSER)) |
1197 | fsuid_only = false; | 1169 | fsuid_only = false; |
diff --git a/fs/cifs/ioctl.c b/fs/cifs/ioctl.c index 077bf756f342..2fa22f20cfc5 100644 --- a/fs/cifs/ioctl.c +++ b/fs/cifs/ioctl.c | |||
@@ -63,8 +63,6 @@ long cifs_ioctl(struct file *filep, unsigned int command, unsigned long arg) | |||
63 | #ifdef CONFIG_CIFS_POSIX | 63 | #ifdef CONFIG_CIFS_POSIX |
64 | case FS_IOC_GETFLAGS: | 64 | case FS_IOC_GETFLAGS: |
65 | if (CIFS_UNIX_EXTATTR_CAP & caps) { | 65 | if (CIFS_UNIX_EXTATTR_CAP & caps) { |
66 | if (pSMBFile == NULL) | ||
67 | break; | ||
68 | rc = CIFSGetExtAttr(xid, tcon, pSMBFile->netfid, | 66 | rc = CIFSGetExtAttr(xid, tcon, pSMBFile->netfid, |
69 | &ExtAttrBits, &ExtAttrMask); | 67 | &ExtAttrBits, &ExtAttrMask); |
70 | if (rc == 0) | 68 | if (rc == 0) |
@@ -80,8 +78,6 @@ long cifs_ioctl(struct file *filep, unsigned int command, unsigned long arg) | |||
80 | rc = -EFAULT; | 78 | rc = -EFAULT; |
81 | break; | 79 | break; |
82 | } | 80 | } |
83 | if (pSMBFile == NULL) | ||
84 | break; | ||
85 | /* rc= CIFSGetExtAttr(xid,tcon,pSMBFile->netfid, | 81 | /* rc= CIFSGetExtAttr(xid,tcon,pSMBFile->netfid, |
86 | extAttrBits, &ExtAttrMask);*/ | 82 | extAttrBits, &ExtAttrMask);*/ |
87 | } | 83 | } |
diff --git a/fs/cifs/misc.c b/fs/cifs/misc.c index c4e296fe3518..43f10281bc19 100644 --- a/fs/cifs/misc.c +++ b/fs/cifs/misc.c | |||
@@ -569,10 +569,9 @@ is_valid_oplock_break(struct smb_hdr *buf, struct TCP_Server_Info *srv) | |||
569 | 569 | ||
570 | cFYI(1, "file id match, oplock break"); | 570 | cFYI(1, "file id match, oplock break"); |
571 | pCifsInode = CIFS_I(netfile->dentry->d_inode); | 571 | pCifsInode = CIFS_I(netfile->dentry->d_inode); |
572 | pCifsInode->clientCanCacheAll = false; | ||
573 | if (pSMB->OplockLevel == 0) | ||
574 | pCifsInode->clientCanCacheRead = false; | ||
575 | 572 | ||
573 | cifs_set_oplock_level(pCifsInode, | ||
574 | pSMB->OplockLevel); | ||
576 | /* | 575 | /* |
577 | * cifs_oplock_break_put() can't be called | 576 | * cifs_oplock_break_put() can't be called |
578 | * from here. Get reference after queueing | 577 | * from here. Get reference after queueing |
@@ -722,3 +721,23 @@ cifs_autodisable_serverino(struct cifs_sb_info *cifs_sb) | |||
722 | cifs_sb_master_tcon(cifs_sb)->treeName); | 721 | cifs_sb_master_tcon(cifs_sb)->treeName); |
723 | } | 722 | } |
724 | } | 723 | } |
724 | |||
725 | void cifs_set_oplock_level(struct cifsInodeInfo *cinode, __u32 oplock) | ||
726 | { | ||
727 | oplock &= 0xF; | ||
728 | |||
729 | if (oplock == OPLOCK_EXCLUSIVE) { | ||
730 | cinode->clientCanCacheAll = true; | ||
731 | cinode->clientCanCacheRead = true; | ||
732 | cFYI(1, "Exclusive Oplock granted on inode %p", | ||
733 | &cinode->vfs_inode); | ||
734 | } else if (oplock == OPLOCK_READ) { | ||
735 | cinode->clientCanCacheAll = false; | ||
736 | cinode->clientCanCacheRead = true; | ||
737 | cFYI(1, "Level II Oplock granted on inode %p", | ||
738 | &cinode->vfs_inode); | ||
739 | } else { | ||
740 | cinode->clientCanCacheAll = false; | ||
741 | cinode->clientCanCacheRead = false; | ||
742 | } | ||
743 | } | ||