diff options
author | Jiri Kosina <jkosina@suse.cz> | 2010-12-22 12:57:02 -0500 |
---|---|---|
committer | Jiri Kosina <jkosina@suse.cz> | 2010-12-22 12:57:02 -0500 |
commit | 4b7bd364700d9ac8372eff48832062b936d0793b (patch) | |
tree | 0dbf78c95456a0b02d07fcd473281f04a87e266d /fs/cifs/connect.c | |
parent | c0d8768af260e2cbb4bf659ae6094a262c86b085 (diff) | |
parent | 90a8a73c06cc32b609a880d48449d7083327e11a (diff) |
Merge branch 'master' into for-next
Conflicts:
MAINTAINERS
arch/arm/mach-omap2/pm24xx.c
drivers/scsi/bfa/bfa_fcpim.c
Needed to update to apply fixes for which the old branch was too
outdated.
Diffstat (limited to 'fs/cifs/connect.c')
-rw-r--r-- | fs/cifs/connect.c | 242 |
1 files changed, 131 insertions, 111 deletions
diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c index 9eb327defa1d..cc1a8604a790 100644 --- a/fs/cifs/connect.c +++ b/fs/cifs/connect.c | |||
@@ -105,6 +105,7 @@ struct smb_vol { | |||
105 | unsigned int wsize; | 105 | unsigned int wsize; |
106 | bool sockopt_tcp_nodelay:1; | 106 | bool sockopt_tcp_nodelay:1; |
107 | unsigned short int port; | 107 | unsigned short int port; |
108 | unsigned long actimeo; /* attribute cache timeout (jiffies) */ | ||
108 | char *prepath; | 109 | char *prepath; |
109 | struct sockaddr_storage srcaddr; /* allow binding to a local IP */ | 110 | struct sockaddr_storage srcaddr; /* allow binding to a local IP */ |
110 | struct nls_table *local_nls; | 111 | struct nls_table *local_nls; |
@@ -116,6 +117,7 @@ struct smb_vol { | |||
116 | 117 | ||
117 | static int ipv4_connect(struct TCP_Server_Info *server); | 118 | static int ipv4_connect(struct TCP_Server_Info *server); |
118 | static int ipv6_connect(struct TCP_Server_Info *server); | 119 | static int ipv6_connect(struct TCP_Server_Info *server); |
120 | static void tlink_rb_insert(struct rb_root *root, struct tcon_link *new_tlink); | ||
119 | static void cifs_prune_tlinks(struct work_struct *work); | 121 | static void cifs_prune_tlinks(struct work_struct *work); |
120 | 122 | ||
121 | /* | 123 | /* |
@@ -805,23 +807,20 @@ cifs_parse_mount_options(char *options, const char *devname, | |||
805 | short int override_gid = -1; | 807 | short int override_gid = -1; |
806 | bool uid_specified = false; | 808 | bool uid_specified = false; |
807 | bool gid_specified = false; | 809 | bool gid_specified = false; |
810 | char *nodename = utsname()->nodename; | ||
808 | 811 | ||
809 | separator[0] = ','; | 812 | separator[0] = ','; |
810 | separator[1] = 0; | 813 | separator[1] = 0; |
811 | 814 | ||
812 | if (Local_System_Name[0] != 0) | 815 | /* |
813 | memcpy(vol->source_rfc1001_name, Local_System_Name, 15); | 816 | * does not have to be perfect mapping since field is |
814 | else { | 817 | * informational, only used for servers that do not support |
815 | char *nodename = utsname()->nodename; | 818 | * port 445 and it can be overridden at mount time |
816 | int n = strnlen(nodename, 15); | 819 | */ |
817 | memset(vol->source_rfc1001_name, 0x20, 15); | 820 | memset(vol->source_rfc1001_name, 0x20, 15); |
818 | for (i = 0; i < n; i++) { | 821 | for (i = 0; i < strnlen(nodename, 15); i++) |
819 | /* does not have to be perfect mapping since field is | 822 | vol->source_rfc1001_name[i] = toupper(nodename[i]); |
820 | informational, only used for servers that do not support | 823 | |
821 | port 445 and it can be overridden at mount time */ | ||
822 | vol->source_rfc1001_name[i] = toupper(nodename[i]); | ||
823 | } | ||
824 | } | ||
825 | vol->source_rfc1001_name[15] = 0; | 824 | vol->source_rfc1001_name[15] = 0; |
826 | /* null target name indicates to use *SMBSERVR default called name | 825 | /* null target name indicates to use *SMBSERVR default called name |
827 | if we end up sending RFC1001 session initialize */ | 826 | if we end up sending RFC1001 session initialize */ |
@@ -839,6 +838,8 @@ cifs_parse_mount_options(char *options, const char *devname, | |||
839 | /* default to using server inode numbers where available */ | 838 | /* default to using server inode numbers where available */ |
840 | vol->server_ino = 1; | 839 | vol->server_ino = 1; |
841 | 840 | ||
841 | vol->actimeo = CIFS_DEF_ACTIMEO; | ||
842 | |||
842 | if (!options) | 843 | if (!options) |
843 | return 1; | 844 | return 1; |
844 | 845 | ||
@@ -1213,6 +1214,16 @@ cifs_parse_mount_options(char *options, const char *devname, | |||
1213 | printk(KERN_WARNING "CIFS: server net" | 1214 | printk(KERN_WARNING "CIFS: server net" |
1214 | "biosname longer than 15 truncated.\n"); | 1215 | "biosname longer than 15 truncated.\n"); |
1215 | } | 1216 | } |
1217 | } else if (strnicmp(data, "actimeo", 7) == 0) { | ||
1218 | if (value && *value) { | ||
1219 | vol->actimeo = HZ * simple_strtoul(value, | ||
1220 | &value, 0); | ||
1221 | if (vol->actimeo > CIFS_MAX_ACTIMEO) { | ||
1222 | cERROR(1, "CIFS: attribute cache" | ||
1223 | "timeout too large"); | ||
1224 | return 1; | ||
1225 | } | ||
1226 | } | ||
1216 | } else if (strnicmp(data, "credentials", 4) == 0) { | 1227 | } else if (strnicmp(data, "credentials", 4) == 0) { |
1217 | /* ignore */ | 1228 | /* ignore */ |
1218 | } else if (strnicmp(data, "version", 3) == 0) { | 1229 | } else if (strnicmp(data, "version", 3) == 0) { |
@@ -1351,6 +1362,11 @@ cifs_parse_mount_options(char *options, const char *devname, | |||
1351 | "supported. Instead set " | 1362 | "supported. Instead set " |
1352 | "/proc/fs/cifs/LookupCacheEnabled to 0\n"); | 1363 | "/proc/fs/cifs/LookupCacheEnabled to 0\n"); |
1353 | } else if (strnicmp(data, "fsc", 3) == 0) { | 1364 | } else if (strnicmp(data, "fsc", 3) == 0) { |
1365 | #ifndef CONFIG_CIFS_FSCACHE | ||
1366 | cERROR(1, "FS-Cache support needs CONFIG_CIFS_FSCACHE" | ||
1367 | "kernel config option set"); | ||
1368 | return 1; | ||
1369 | #endif | ||
1354 | vol->fsc = true; | 1370 | vol->fsc = true; |
1355 | } else if (strnicmp(data, "mfsymlinks", 10) == 0) { | 1371 | } else if (strnicmp(data, "mfsymlinks", 10) == 0) { |
1356 | vol->mfsymlinks = true; | 1372 | vol->mfsymlinks = true; |
@@ -2565,6 +2581,8 @@ static void setup_cifs_sb(struct smb_vol *pvolume_info, | |||
2565 | cFYI(1, "file mode: 0x%x dir mode: 0x%x", | 2581 | cFYI(1, "file mode: 0x%x dir mode: 0x%x", |
2566 | cifs_sb->mnt_file_mode, cifs_sb->mnt_dir_mode); | 2582 | cifs_sb->mnt_file_mode, cifs_sb->mnt_dir_mode); |
2567 | 2583 | ||
2584 | cifs_sb->actimeo = pvolume_info->actimeo; | ||
2585 | |||
2568 | if (pvolume_info->noperm) | 2586 | if (pvolume_info->noperm) |
2569 | cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NO_PERM; | 2587 | cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NO_PERM; |
2570 | if (pvolume_info->setuids) | 2588 | if (pvolume_info->setuids) |
@@ -2815,13 +2833,13 @@ remote_path_check: | |||
2815 | /* check if a whole path (including prepath) is not remote */ | 2833 | /* check if a whole path (including prepath) is not remote */ |
2816 | if (!rc && cifs_sb->prepathlen && tcon) { | 2834 | if (!rc && cifs_sb->prepathlen && tcon) { |
2817 | /* build_path_to_root works only when we have a valid tcon */ | 2835 | /* build_path_to_root works only when we have a valid tcon */ |
2818 | full_path = cifs_build_path_to_root(cifs_sb); | 2836 | full_path = cifs_build_path_to_root(cifs_sb, tcon); |
2819 | if (full_path == NULL) { | 2837 | if (full_path == NULL) { |
2820 | rc = -ENOMEM; | 2838 | rc = -ENOMEM; |
2821 | goto mount_fail_check; | 2839 | goto mount_fail_check; |
2822 | } | 2840 | } |
2823 | rc = is_path_accessible(xid, tcon, cifs_sb, full_path); | 2841 | rc = is_path_accessible(xid, tcon, cifs_sb, full_path); |
2824 | if (rc != -EREMOTE) { | 2842 | if (rc != 0 && rc != -EREMOTE) { |
2825 | kfree(full_path); | 2843 | kfree(full_path); |
2826 | goto mount_fail_check; | 2844 | goto mount_fail_check; |
2827 | } | 2845 | } |
@@ -2900,24 +2918,16 @@ remote_path_check: | |||
2900 | goto mount_fail_check; | 2918 | goto mount_fail_check; |
2901 | } | 2919 | } |
2902 | 2920 | ||
2903 | tlink->tl_index = pSesInfo->linux_uid; | 2921 | tlink->tl_uid = pSesInfo->linux_uid; |
2904 | tlink->tl_tcon = tcon; | 2922 | tlink->tl_tcon = tcon; |
2905 | tlink->tl_time = jiffies; | 2923 | tlink->tl_time = jiffies; |
2906 | set_bit(TCON_LINK_MASTER, &tlink->tl_flags); | 2924 | set_bit(TCON_LINK_MASTER, &tlink->tl_flags); |
2907 | set_bit(TCON_LINK_IN_TREE, &tlink->tl_flags); | 2925 | set_bit(TCON_LINK_IN_TREE, &tlink->tl_flags); |
2908 | 2926 | ||
2909 | rc = radix_tree_preload(GFP_KERNEL); | 2927 | 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); | 2928 | spin_lock(&cifs_sb->tlink_tree_lock); |
2916 | radix_tree_insert(&cifs_sb->tlink_tree, pSesInfo->linux_uid, tlink); | 2929 | 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); | 2930 | spin_unlock(&cifs_sb->tlink_tree_lock); |
2920 | radix_tree_preload_end(); | ||
2921 | 2931 | ||
2922 | queue_delayed_work(system_nrt_wq, &cifs_sb->prune_tlinks, | 2932 | queue_delayed_work(system_nrt_wq, &cifs_sb->prune_tlinks, |
2923 | TLINK_IDLE_EXPIRE); | 2933 | TLINK_IDLE_EXPIRE); |
@@ -3107,32 +3117,25 @@ CIFSTCon(unsigned int xid, struct cifsSesInfo *ses, | |||
3107 | int | 3117 | int |
3108 | cifs_umount(struct super_block *sb, struct cifs_sb_info *cifs_sb) | 3118 | cifs_umount(struct super_block *sb, struct cifs_sb_info *cifs_sb) |
3109 | { | 3119 | { |
3110 | int i, ret; | 3120 | struct rb_root *root = &cifs_sb->tlink_tree; |
3121 | struct rb_node *node; | ||
3122 | struct tcon_link *tlink; | ||
3111 | char *tmp; | 3123 | char *tmp; |
3112 | struct tcon_link *tlink[8]; | ||
3113 | unsigned long index = 0; | ||
3114 | 3124 | ||
3115 | cancel_delayed_work_sync(&cifs_sb->prune_tlinks); | 3125 | cancel_delayed_work_sync(&cifs_sb->prune_tlinks); |
3116 | 3126 | ||
3117 | do { | 3127 | spin_lock(&cifs_sb->tlink_tree_lock); |
3118 | spin_lock(&cifs_sb->tlink_tree_lock); | 3128 | while ((node = rb_first(root))) { |
3119 | ret = radix_tree_gang_lookup(&cifs_sb->tlink_tree, | 3129 | tlink = rb_entry(node, struct tcon_link, tl_rbnode); |
3120 | (void **)tlink, index, | 3130 | cifs_get_tlink(tlink); |
3121 | ARRAY_SIZE(tlink)); | 3131 | clear_bit(TCON_LINK_IN_TREE, &tlink->tl_flags); |
3122 | /* increment index for next pass */ | 3132 | 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 | 3133 | ||
3133 | for (i = 0; i < ret; i++) | 3134 | spin_unlock(&cifs_sb->tlink_tree_lock); |
3134 | cifs_put_tlink(tlink[i]); | 3135 | cifs_put_tlink(tlink); |
3135 | } while (ret != 0); | 3136 | spin_lock(&cifs_sb->tlink_tree_lock); |
3137 | } | ||
3138 | spin_unlock(&cifs_sb->tlink_tree_lock); | ||
3136 | 3139 | ||
3137 | tmp = cifs_sb->prepath; | 3140 | tmp = cifs_sb->prepath; |
3138 | cifs_sb->prepathlen = 0; | 3141 | cifs_sb->prepathlen = 0; |
@@ -3271,22 +3274,10 @@ out: | |||
3271 | return tcon; | 3274 | return tcon; |
3272 | } | 3275 | } |
3273 | 3276 | ||
3274 | static struct tcon_link * | 3277 | static inline struct tcon_link * |
3275 | cifs_sb_master_tlink(struct cifs_sb_info *cifs_sb) | 3278 | cifs_sb_master_tlink(struct cifs_sb_info *cifs_sb) |
3276 | { | 3279 | { |
3277 | struct tcon_link *tlink; | 3280 | 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 | } | 3281 | } |
3291 | 3282 | ||
3292 | struct cifsTconInfo * | 3283 | struct cifsTconInfo * |
@@ -3302,6 +3293,47 @@ cifs_sb_tcon_pending_wait(void *unused) | |||
3302 | return signal_pending(current) ? -ERESTARTSYS : 0; | 3293 | return signal_pending(current) ? -ERESTARTSYS : 0; |
3303 | } | 3294 | } |
3304 | 3295 | ||
3296 | /* find and return a tlink with given uid */ | ||
3297 | static struct tcon_link * | ||
3298 | tlink_rb_search(struct rb_root *root, uid_t uid) | ||
3299 | { | ||
3300 | struct rb_node *node = root->rb_node; | ||
3301 | struct tcon_link *tlink; | ||
3302 | |||
3303 | while (node) { | ||
3304 | tlink = rb_entry(node, struct tcon_link, tl_rbnode); | ||
3305 | |||
3306 | if (tlink->tl_uid > uid) | ||
3307 | node = node->rb_left; | ||
3308 | else if (tlink->tl_uid < uid) | ||
3309 | node = node->rb_right; | ||
3310 | else | ||
3311 | return tlink; | ||
3312 | } | ||
3313 | return NULL; | ||
3314 | } | ||
3315 | |||
3316 | /* insert a tcon_link into the tree */ | ||
3317 | static void | ||
3318 | tlink_rb_insert(struct rb_root *root, struct tcon_link *new_tlink) | ||
3319 | { | ||
3320 | struct rb_node **new = &(root->rb_node), *parent = NULL; | ||
3321 | struct tcon_link *tlink; | ||
3322 | |||
3323 | while (*new) { | ||
3324 | tlink = rb_entry(*new, struct tcon_link, tl_rbnode); | ||
3325 | parent = *new; | ||
3326 | |||
3327 | if (tlink->tl_uid > new_tlink->tl_uid) | ||
3328 | new = &((*new)->rb_left); | ||
3329 | else | ||
3330 | new = &((*new)->rb_right); | ||
3331 | } | ||
3332 | |||
3333 | rb_link_node(&new_tlink->tl_rbnode, parent, new); | ||
3334 | rb_insert_color(&new_tlink->tl_rbnode, root); | ||
3335 | } | ||
3336 | |||
3305 | /* | 3337 | /* |
3306 | * Find or construct an appropriate tcon given a cifs_sb and the fsuid of the | 3338 | * Find or construct an appropriate tcon given a cifs_sb and the fsuid of the |
3307 | * current task. | 3339 | * current task. |
@@ -3309,7 +3341,7 @@ cifs_sb_tcon_pending_wait(void *unused) | |||
3309 | * If the superblock doesn't refer to a multiuser mount, then just return | 3341 | * If the superblock doesn't refer to a multiuser mount, then just return |
3310 | * the master tcon for the mount. | 3342 | * the master tcon for the mount. |
3311 | * | 3343 | * |
3312 | * First, search the radix tree for an existing tcon for this fsuid. If one | 3344 | * 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 | 3345 | * 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 | 3346 | * 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 | 3347 | * it failed and either return an error or retry construction, depending on |
@@ -3322,14 +3354,14 @@ struct tcon_link * | |||
3322 | cifs_sb_tlink(struct cifs_sb_info *cifs_sb) | 3354 | cifs_sb_tlink(struct cifs_sb_info *cifs_sb) |
3323 | { | 3355 | { |
3324 | int ret; | 3356 | int ret; |
3325 | unsigned long fsuid = (unsigned long) current_fsuid(); | 3357 | uid_t fsuid = current_fsuid(); |
3326 | struct tcon_link *tlink, *newtlink; | 3358 | struct tcon_link *tlink, *newtlink; |
3327 | 3359 | ||
3328 | if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MULTIUSER)) | 3360 | if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MULTIUSER)) |
3329 | return cifs_get_tlink(cifs_sb_master_tlink(cifs_sb)); | 3361 | return cifs_get_tlink(cifs_sb_master_tlink(cifs_sb)); |
3330 | 3362 | ||
3331 | spin_lock(&cifs_sb->tlink_tree_lock); | 3363 | spin_lock(&cifs_sb->tlink_tree_lock); |
3332 | tlink = radix_tree_lookup(&cifs_sb->tlink_tree, fsuid); | 3364 | tlink = tlink_rb_search(&cifs_sb->tlink_tree, fsuid); |
3333 | if (tlink) | 3365 | if (tlink) |
3334 | cifs_get_tlink(tlink); | 3366 | cifs_get_tlink(tlink); |
3335 | spin_unlock(&cifs_sb->tlink_tree_lock); | 3367 | spin_unlock(&cifs_sb->tlink_tree_lock); |
@@ -3338,36 +3370,24 @@ cifs_sb_tlink(struct cifs_sb_info *cifs_sb) | |||
3338 | newtlink = kzalloc(sizeof(*tlink), GFP_KERNEL); | 3370 | newtlink = kzalloc(sizeof(*tlink), GFP_KERNEL); |
3339 | if (newtlink == NULL) | 3371 | if (newtlink == NULL) |
3340 | return ERR_PTR(-ENOMEM); | 3372 | return ERR_PTR(-ENOMEM); |
3341 | newtlink->tl_index = fsuid; | 3373 | newtlink->tl_uid = fsuid; |
3342 | newtlink->tl_tcon = ERR_PTR(-EACCES); | 3374 | newtlink->tl_tcon = ERR_PTR(-EACCES); |
3343 | set_bit(TCON_LINK_PENDING, &newtlink->tl_flags); | 3375 | set_bit(TCON_LINK_PENDING, &newtlink->tl_flags); |
3344 | set_bit(TCON_LINK_IN_TREE, &newtlink->tl_flags); | 3376 | set_bit(TCON_LINK_IN_TREE, &newtlink->tl_flags); |
3345 | cifs_get_tlink(newtlink); | 3377 | cifs_get_tlink(newtlink); |
3346 | 3378 | ||
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); | 3379 | spin_lock(&cifs_sb->tlink_tree_lock); |
3354 | /* was one inserted after previous search? */ | 3380 | /* was one inserted after previous search? */ |
3355 | tlink = radix_tree_lookup(&cifs_sb->tlink_tree, fsuid); | 3381 | tlink = tlink_rb_search(&cifs_sb->tlink_tree, fsuid); |
3356 | if (tlink) { | 3382 | if (tlink) { |
3357 | cifs_get_tlink(tlink); | 3383 | cifs_get_tlink(tlink); |
3358 | spin_unlock(&cifs_sb->tlink_tree_lock); | 3384 | spin_unlock(&cifs_sb->tlink_tree_lock); |
3359 | radix_tree_preload_end(); | ||
3360 | kfree(newtlink); | 3385 | kfree(newtlink); |
3361 | goto wait_for_construction; | 3386 | goto wait_for_construction; |
3362 | } | 3387 | } |
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; | 3388 | tlink = newtlink; |
3389 | tlink_rb_insert(&cifs_sb->tlink_tree, tlink); | ||
3390 | spin_unlock(&cifs_sb->tlink_tree_lock); | ||
3371 | } else { | 3391 | } else { |
3372 | wait_for_construction: | 3392 | wait_for_construction: |
3373 | ret = wait_on_bit(&tlink->tl_flags, TCON_LINK_PENDING, | 3393 | ret = wait_on_bit(&tlink->tl_flags, TCON_LINK_PENDING, |
@@ -3413,39 +3433,39 @@ cifs_prune_tlinks(struct work_struct *work) | |||
3413 | { | 3433 | { |
3414 | struct cifs_sb_info *cifs_sb = container_of(work, struct cifs_sb_info, | 3434 | struct cifs_sb_info *cifs_sb = container_of(work, struct cifs_sb_info, |
3415 | prune_tlinks.work); | 3435 | prune_tlinks.work); |
3416 | struct tcon_link *tlink[8]; | 3436 | struct rb_root *root = &cifs_sb->tlink_tree; |
3417 | unsigned long now = jiffies; | 3437 | struct rb_node *node = rb_first(root); |
3418 | unsigned long index = 0; | 3438 | struct rb_node *tmp; |
3419 | int i, ret; | 3439 | struct tcon_link *tlink; |
3420 | 3440 | ||
3421 | do { | 3441 | /* |
3422 | spin_lock(&cifs_sb->tlink_tree_lock); | 3442 | * Because we drop the spinlock in the loop in order to put the tlink |
3423 | ret = radix_tree_gang_lookup(&cifs_sb->tlink_tree, | 3443 | * it's not guarded against removal of links from the tree. The only |
3424 | (void **)tlink, index, | 3444 | * places that remove entries from the tree are this function and |
3425 | ARRAY_SIZE(tlink)); | 3445 | * umounts. Because this function is non-reentrant and is canceled |
3426 | /* increment index for next pass */ | 3446 | * before umount can proceed, this is safe. |
3427 | if (ret > 0) | 3447 | */ |
3428 | index = tlink[ret - 1]->tl_index + 1; | 3448 | spin_lock(&cifs_sb->tlink_tree_lock); |
3429 | for (i = 0; i < ret; i++) { | 3449 | node = rb_first(root); |
3430 | if (test_bit(TCON_LINK_MASTER, &tlink[i]->tl_flags) || | 3450 | while (node != NULL) { |
3431 | atomic_read(&tlink[i]->tl_count) != 0 || | 3451 | tmp = node; |
3432 | time_after(tlink[i]->tl_time + TLINK_IDLE_EXPIRE, | 3452 | node = rb_next(tmp); |
3433 | now)) { | 3453 | tlink = rb_entry(tmp, struct tcon_link, tl_rbnode); |
3434 | tlink[i] = NULL; | 3454 | |
3435 | continue; | 3455 | if (test_bit(TCON_LINK_MASTER, &tlink->tl_flags) || |
3436 | } | 3456 | atomic_read(&tlink->tl_count) != 0 || |
3437 | cifs_get_tlink(tlink[i]); | 3457 | time_after(tlink->tl_time + TLINK_IDLE_EXPIRE, jiffies)) |
3438 | clear_bit(TCON_LINK_IN_TREE, &tlink[i]->tl_flags); | 3458 | continue; |
3439 | radix_tree_delete(&cifs_sb->tlink_tree, | ||
3440 | tlink[i]->tl_index); | ||
3441 | } | ||
3442 | spin_unlock(&cifs_sb->tlink_tree_lock); | ||
3443 | 3459 | ||
3444 | for (i = 0; i < ret; i++) { | 3460 | cifs_get_tlink(tlink); |
3445 | if (tlink[i] != NULL) | 3461 | clear_bit(TCON_LINK_IN_TREE, &tlink->tl_flags); |
3446 | cifs_put_tlink(tlink[i]); | 3462 | rb_erase(tmp, root); |
3447 | } | 3463 | |
3448 | } while (ret != 0); | 3464 | spin_unlock(&cifs_sb->tlink_tree_lock); |
3465 | cifs_put_tlink(tlink); | ||
3466 | spin_lock(&cifs_sb->tlink_tree_lock); | ||
3467 | } | ||
3468 | spin_unlock(&cifs_sb->tlink_tree_lock); | ||
3449 | 3469 | ||
3450 | queue_delayed_work(system_nrt_wq, &cifs_sb->prune_tlinks, | 3470 | queue_delayed_work(system_nrt_wq, &cifs_sb->prune_tlinks, |
3451 | TLINK_IDLE_EXPIRE); | 3471 | TLINK_IDLE_EXPIRE); |