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 | } | ||
