diff options
author | Alex Elder <aelder@sgi.com> | 2010-08-02 11:24:57 -0400 |
---|---|---|
committer | Alex Elder <aelder@sgi.com> | 2010-08-02 11:24:57 -0400 |
commit | 6b0a2996a0c023d84bc27ec7528a6e54cb5ea264 (patch) | |
tree | 9fa9a85d5d871b3cb3c28daf57d8ef8f05becd66 /fs | |
parent | 209fb87a259ead17e966627b7f053d16a96898da (diff) | |
parent | 9fe6206f400646a2322096b56c59891d530e8d51 (diff) |
Merge branch 'v2.6.35'
Diffstat (limited to 'fs')
-rw-r--r-- | fs/9p/vfs_dir.c | 2 | ||||
-rw-r--r-- | fs/ceph/Kconfig | 2 | ||||
-rw-r--r-- | fs/ceph/caps.c | 15 | ||||
-rw-r--r-- | fs/ceph/dir.c | 13 | ||||
-rw-r--r-- | fs/ceph/file.c | 2 | ||||
-rw-r--r-- | fs/ceph/inode.c | 6 | ||||
-rw-r--r-- | fs/ceph/mds_client.c | 10 | ||||
-rw-r--r-- | fs/ceph/mon_client.c | 6 | ||||
-rw-r--r-- | fs/ceph/osd_client.c | 6 | ||||
-rw-r--r-- | fs/ceph/osdmap.c | 26 | ||||
-rw-r--r-- | fs/cifs/dns_resolve.c | 2 | ||||
-rw-r--r-- | fs/cifs/dns_resolve.h | 2 | ||||
-rw-r--r-- | fs/ecryptfs/messaging.c | 17 | ||||
-rw-r--r-- | fs/gfs2/dir.c | 31 | ||||
-rw-r--r-- | fs/nfs/file.c | 13 | ||||
-rw-r--r-- | fs/nfs/nfsroot.c | 2 | ||||
-rw-r--r-- | fs/nfs/write.c | 30 | ||||
-rw-r--r-- | fs/proc/array.c | 2 | ||||
-rw-r--r-- | fs/sysfs/symlink.c | 26 |
19 files changed, 138 insertions, 75 deletions
diff --git a/fs/9p/vfs_dir.c b/fs/9p/vfs_dir.c index d61e3b28ce37..36d961f342af 100644 --- a/fs/9p/vfs_dir.c +++ b/fs/9p/vfs_dir.c | |||
@@ -146,7 +146,7 @@ static int v9fs_dir_readdir(struct file *filp, void *dirent, filldir_t filldir) | |||
146 | while (rdir->head < rdir->tail) { | 146 | while (rdir->head < rdir->tail) { |
147 | p9stat_init(&st); | 147 | p9stat_init(&st); |
148 | err = p9stat_read(rdir->buf + rdir->head, | 148 | err = p9stat_read(rdir->buf + rdir->head, |
149 | buflen - rdir->head, &st, | 149 | rdir->tail - rdir->head, &st, |
150 | fid->clnt->proto_version); | 150 | fid->clnt->proto_version); |
151 | if (err) { | 151 | if (err) { |
152 | P9_DPRINTK(P9_DEBUG_VFS, "returned %d\n", err); | 152 | P9_DPRINTK(P9_DEBUG_VFS, "returned %d\n", err); |
diff --git a/fs/ceph/Kconfig b/fs/ceph/Kconfig index 04b8280582a9..bc87b9c1d27e 100644 --- a/fs/ceph/Kconfig +++ b/fs/ceph/Kconfig | |||
@@ -2,7 +2,7 @@ config CEPH_FS | |||
2 | tristate "Ceph distributed file system (EXPERIMENTAL)" | 2 | tristate "Ceph distributed file system (EXPERIMENTAL)" |
3 | depends on INET && EXPERIMENTAL | 3 | depends on INET && EXPERIMENTAL |
4 | select LIBCRC32C | 4 | select LIBCRC32C |
5 | select CONFIG_CRYPTO_AES | 5 | select CRYPTO_AES |
6 | help | 6 | help |
7 | Choose Y or M here to include support for mounting the | 7 | Choose Y or M here to include support for mounting the |
8 | experimental Ceph distributed file system. Ceph is an extremely | 8 | experimental Ceph distributed file system. Ceph is an extremely |
diff --git a/fs/ceph/caps.c b/fs/ceph/caps.c index 74144d6389f0..b81be9a56487 100644 --- a/fs/ceph/caps.c +++ b/fs/ceph/caps.c | |||
@@ -627,7 +627,7 @@ retry: | |||
627 | if (fmode >= 0) | 627 | if (fmode >= 0) |
628 | __ceph_get_fmode(ci, fmode); | 628 | __ceph_get_fmode(ci, fmode); |
629 | spin_unlock(&inode->i_lock); | 629 | spin_unlock(&inode->i_lock); |
630 | wake_up(&ci->i_cap_wq); | 630 | wake_up_all(&ci->i_cap_wq); |
631 | return 0; | 631 | return 0; |
632 | } | 632 | } |
633 | 633 | ||
@@ -1181,7 +1181,7 @@ static int __send_cap(struct ceph_mds_client *mdsc, struct ceph_cap *cap, | |||
1181 | } | 1181 | } |
1182 | 1182 | ||
1183 | if (wake) | 1183 | if (wake) |
1184 | wake_up(&ci->i_cap_wq); | 1184 | wake_up_all(&ci->i_cap_wq); |
1185 | 1185 | ||
1186 | return delayed; | 1186 | return delayed; |
1187 | } | 1187 | } |
@@ -2153,7 +2153,7 @@ void ceph_put_cap_refs(struct ceph_inode_info *ci, int had) | |||
2153 | else if (flushsnaps) | 2153 | else if (flushsnaps) |
2154 | ceph_flush_snaps(ci); | 2154 | ceph_flush_snaps(ci); |
2155 | if (wake) | 2155 | if (wake) |
2156 | wake_up(&ci->i_cap_wq); | 2156 | wake_up_all(&ci->i_cap_wq); |
2157 | if (put) | 2157 | if (put) |
2158 | iput(inode); | 2158 | iput(inode); |
2159 | } | 2159 | } |
@@ -2229,7 +2229,7 @@ void ceph_put_wrbuffer_cap_refs(struct ceph_inode_info *ci, int nr, | |||
2229 | iput(inode); | 2229 | iput(inode); |
2230 | } else if (complete_capsnap) { | 2230 | } else if (complete_capsnap) { |
2231 | ceph_flush_snaps(ci); | 2231 | ceph_flush_snaps(ci); |
2232 | wake_up(&ci->i_cap_wq); | 2232 | wake_up_all(&ci->i_cap_wq); |
2233 | } | 2233 | } |
2234 | if (drop_capsnap) | 2234 | if (drop_capsnap) |
2235 | iput(inode); | 2235 | iput(inode); |
@@ -2405,7 +2405,7 @@ static void handle_cap_grant(struct inode *inode, struct ceph_mds_caps *grant, | |||
2405 | if (queue_invalidate) | 2405 | if (queue_invalidate) |
2406 | ceph_queue_invalidate(inode); | 2406 | ceph_queue_invalidate(inode); |
2407 | if (wake) | 2407 | if (wake) |
2408 | wake_up(&ci->i_cap_wq); | 2408 | wake_up_all(&ci->i_cap_wq); |
2409 | 2409 | ||
2410 | if (check_caps == 1) | 2410 | if (check_caps == 1) |
2411 | ceph_check_caps(ci, CHECK_CAPS_NODELAY|CHECK_CAPS_AUTHONLY, | 2411 | ceph_check_caps(ci, CHECK_CAPS_NODELAY|CHECK_CAPS_AUTHONLY, |
@@ -2460,7 +2460,7 @@ static void handle_cap_flush_ack(struct inode *inode, u64 flush_tid, | |||
2460 | struct ceph_inode_info, | 2460 | struct ceph_inode_info, |
2461 | i_flushing_item)->vfs_inode); | 2461 | i_flushing_item)->vfs_inode); |
2462 | mdsc->num_cap_flushing--; | 2462 | mdsc->num_cap_flushing--; |
2463 | wake_up(&mdsc->cap_flushing_wq); | 2463 | wake_up_all(&mdsc->cap_flushing_wq); |
2464 | dout(" inode %p now !flushing\n", inode); | 2464 | dout(" inode %p now !flushing\n", inode); |
2465 | 2465 | ||
2466 | if (ci->i_dirty_caps == 0) { | 2466 | if (ci->i_dirty_caps == 0) { |
@@ -2472,7 +2472,7 @@ static void handle_cap_flush_ack(struct inode *inode, u64 flush_tid, | |||
2472 | } | 2472 | } |
2473 | } | 2473 | } |
2474 | spin_unlock(&mdsc->cap_dirty_lock); | 2474 | spin_unlock(&mdsc->cap_dirty_lock); |
2475 | wake_up(&ci->i_cap_wq); | 2475 | wake_up_all(&ci->i_cap_wq); |
2476 | 2476 | ||
2477 | out: | 2477 | out: |
2478 | spin_unlock(&inode->i_lock); | 2478 | spin_unlock(&inode->i_lock); |
@@ -2984,6 +2984,7 @@ int ceph_encode_dentry_release(void **p, struct dentry *dentry, | |||
2984 | memcpy(*p, dentry->d_name.name, dentry->d_name.len); | 2984 | memcpy(*p, dentry->d_name.name, dentry->d_name.len); |
2985 | *p += dentry->d_name.len; | 2985 | *p += dentry->d_name.len; |
2986 | rel->dname_seq = cpu_to_le32(di->lease_seq); | 2986 | rel->dname_seq = cpu_to_le32(di->lease_seq); |
2987 | __ceph_mdsc_drop_dentry_lease(dentry); | ||
2987 | } | 2988 | } |
2988 | spin_unlock(&dentry->d_lock); | 2989 | spin_unlock(&dentry->d_lock); |
2989 | return ret; | 2990 | return ret; |
diff --git a/fs/ceph/dir.c b/fs/ceph/dir.c index f85719310db2..f94ed3c7f6a5 100644 --- a/fs/ceph/dir.c +++ b/fs/ceph/dir.c | |||
@@ -266,6 +266,7 @@ static int ceph_readdir(struct file *filp, void *dirent, filldir_t filldir) | |||
266 | spin_lock(&inode->i_lock); | 266 | spin_lock(&inode->i_lock); |
267 | if ((filp->f_pos == 2 || fi->dentry) && | 267 | if ((filp->f_pos == 2 || fi->dentry) && |
268 | !ceph_test_opt(client, NOASYNCREADDIR) && | 268 | !ceph_test_opt(client, NOASYNCREADDIR) && |
269 | ceph_snap(inode) != CEPH_SNAPDIR && | ||
269 | (ci->i_ceph_flags & CEPH_I_COMPLETE) && | 270 | (ci->i_ceph_flags & CEPH_I_COMPLETE) && |
270 | __ceph_caps_issued_mask(ci, CEPH_CAP_FILE_SHARED, 1)) { | 271 | __ceph_caps_issued_mask(ci, CEPH_CAP_FILE_SHARED, 1)) { |
271 | err = __dcache_readdir(filp, dirent, filldir); | 272 | err = __dcache_readdir(filp, dirent, filldir); |
@@ -1013,18 +1014,22 @@ out_touch: | |||
1013 | 1014 | ||
1014 | /* | 1015 | /* |
1015 | * When a dentry is released, clear the dir I_COMPLETE if it was part | 1016 | * When a dentry is released, clear the dir I_COMPLETE if it was part |
1016 | * of the current dir gen. | 1017 | * of the current dir gen or if this is in the snapshot namespace. |
1017 | */ | 1018 | */ |
1018 | static void ceph_dentry_release(struct dentry *dentry) | 1019 | static void ceph_dentry_release(struct dentry *dentry) |
1019 | { | 1020 | { |
1020 | struct ceph_dentry_info *di = ceph_dentry(dentry); | 1021 | struct ceph_dentry_info *di = ceph_dentry(dentry); |
1021 | struct inode *parent_inode = dentry->d_parent->d_inode; | 1022 | struct inode *parent_inode = dentry->d_parent->d_inode; |
1023 | u64 snapid = ceph_snap(parent_inode); | ||
1022 | 1024 | ||
1023 | if (parent_inode) { | 1025 | dout("dentry_release %p parent %p\n", dentry, parent_inode); |
1026 | |||
1027 | if (parent_inode && snapid != CEPH_SNAPDIR) { | ||
1024 | struct ceph_inode_info *ci = ceph_inode(parent_inode); | 1028 | struct ceph_inode_info *ci = ceph_inode(parent_inode); |
1025 | 1029 | ||
1026 | spin_lock(&parent_inode->i_lock); | 1030 | spin_lock(&parent_inode->i_lock); |
1027 | if (ci->i_shared_gen == di->lease_shared_gen) { | 1031 | if (ci->i_shared_gen == di->lease_shared_gen || |
1032 | snapid <= CEPH_MAXSNAP) { | ||
1028 | dout(" clearing %p complete (d_release)\n", | 1033 | dout(" clearing %p complete (d_release)\n", |
1029 | parent_inode); | 1034 | parent_inode); |
1030 | ci->i_ceph_flags &= ~CEPH_I_COMPLETE; | 1035 | ci->i_ceph_flags &= ~CEPH_I_COMPLETE; |
@@ -1241,7 +1246,9 @@ struct dentry_operations ceph_dentry_ops = { | |||
1241 | 1246 | ||
1242 | struct dentry_operations ceph_snapdir_dentry_ops = { | 1247 | struct dentry_operations ceph_snapdir_dentry_ops = { |
1243 | .d_revalidate = ceph_snapdir_d_revalidate, | 1248 | .d_revalidate = ceph_snapdir_d_revalidate, |
1249 | .d_release = ceph_dentry_release, | ||
1244 | }; | 1250 | }; |
1245 | 1251 | ||
1246 | struct dentry_operations ceph_snap_dentry_ops = { | 1252 | struct dentry_operations ceph_snap_dentry_ops = { |
1253 | .d_release = ceph_dentry_release, | ||
1247 | }; | 1254 | }; |
diff --git a/fs/ceph/file.c b/fs/ceph/file.c index 6251a1574b94..7c08698fad3e 100644 --- a/fs/ceph/file.c +++ b/fs/ceph/file.c | |||
@@ -265,7 +265,7 @@ int ceph_release(struct inode *inode, struct file *file) | |||
265 | kmem_cache_free(ceph_file_cachep, cf); | 265 | kmem_cache_free(ceph_file_cachep, cf); |
266 | 266 | ||
267 | /* wake up anyone waiting for caps on this inode */ | 267 | /* wake up anyone waiting for caps on this inode */ |
268 | wake_up(&ci->i_cap_wq); | 268 | wake_up_all(&ci->i_cap_wq); |
269 | return 0; | 269 | return 0; |
270 | } | 270 | } |
271 | 271 | ||
diff --git a/fs/ceph/inode.c b/fs/ceph/inode.c index 8f9b9fe8ef9f..389f9dbd9949 100644 --- a/fs/ceph/inode.c +++ b/fs/ceph/inode.c | |||
@@ -1199,8 +1199,10 @@ retry_lookup: | |||
1199 | goto out; | 1199 | goto out; |
1200 | } | 1200 | } |
1201 | err = ceph_init_dentry(dn); | 1201 | err = ceph_init_dentry(dn); |
1202 | if (err < 0) | 1202 | if (err < 0) { |
1203 | dput(dn); | ||
1203 | goto out; | 1204 | goto out; |
1205 | } | ||
1204 | } else if (dn->d_inode && | 1206 | } else if (dn->d_inode && |
1205 | (ceph_ino(dn->d_inode) != vino.ino || | 1207 | (ceph_ino(dn->d_inode) != vino.ino || |
1206 | ceph_snap(dn->d_inode) != vino.snap)) { | 1208 | ceph_snap(dn->d_inode) != vino.snap)) { |
@@ -1499,7 +1501,7 @@ retry: | |||
1499 | if (wrbuffer_refs == 0) | 1501 | if (wrbuffer_refs == 0) |
1500 | ceph_check_caps(ci, CHECK_CAPS_AUTHONLY, NULL); | 1502 | ceph_check_caps(ci, CHECK_CAPS_AUTHONLY, NULL); |
1501 | if (wake) | 1503 | if (wake) |
1502 | wake_up(&ci->i_cap_wq); | 1504 | wake_up_all(&ci->i_cap_wq); |
1503 | } | 1505 | } |
1504 | 1506 | ||
1505 | 1507 | ||
diff --git a/fs/ceph/mds_client.c b/fs/ceph/mds_client.c index 416c08d315db..dd440bd438a9 100644 --- a/fs/ceph/mds_client.c +++ b/fs/ceph/mds_client.c | |||
@@ -868,7 +868,7 @@ static int wake_up_session_cb(struct inode *inode, struct ceph_cap *cap, | |||
868 | { | 868 | { |
869 | struct ceph_inode_info *ci = ceph_inode(inode); | 869 | struct ceph_inode_info *ci = ceph_inode(inode); |
870 | 870 | ||
871 | wake_up(&ci->i_cap_wq); | 871 | wake_up_all(&ci->i_cap_wq); |
872 | if (arg) { | 872 | if (arg) { |
873 | spin_lock(&inode->i_lock); | 873 | spin_lock(&inode->i_lock); |
874 | ci->i_wanted_max_size = 0; | 874 | ci->i_wanted_max_size = 0; |
@@ -1564,7 +1564,7 @@ static void complete_request(struct ceph_mds_client *mdsc, | |||
1564 | if (req->r_callback) | 1564 | if (req->r_callback) |
1565 | req->r_callback(mdsc, req); | 1565 | req->r_callback(mdsc, req); |
1566 | else | 1566 | else |
1567 | complete(&req->r_completion); | 1567 | complete_all(&req->r_completion); |
1568 | } | 1568 | } |
1569 | 1569 | ||
1570 | /* | 1570 | /* |
@@ -1932,7 +1932,7 @@ static void handle_reply(struct ceph_mds_session *session, struct ceph_msg *msg) | |||
1932 | if (head->safe) { | 1932 | if (head->safe) { |
1933 | req->r_got_safe = true; | 1933 | req->r_got_safe = true; |
1934 | __unregister_request(mdsc, req); | 1934 | __unregister_request(mdsc, req); |
1935 | complete(&req->r_safe_completion); | 1935 | complete_all(&req->r_safe_completion); |
1936 | 1936 | ||
1937 | if (req->r_got_unsafe) { | 1937 | if (req->r_got_unsafe) { |
1938 | /* | 1938 | /* |
@@ -1947,7 +1947,7 @@ static void handle_reply(struct ceph_mds_session *session, struct ceph_msg *msg) | |||
1947 | 1947 | ||
1948 | /* last unsafe request during umount? */ | 1948 | /* last unsafe request during umount? */ |
1949 | if (mdsc->stopping && !__get_oldest_req(mdsc)) | 1949 | if (mdsc->stopping && !__get_oldest_req(mdsc)) |
1950 | complete(&mdsc->safe_umount_waiters); | 1950 | complete_all(&mdsc->safe_umount_waiters); |
1951 | mutex_unlock(&mdsc->mutex); | 1951 | mutex_unlock(&mdsc->mutex); |
1952 | goto out; | 1952 | goto out; |
1953 | } | 1953 | } |
@@ -2126,7 +2126,7 @@ static void handle_session(struct ceph_mds_session *session, | |||
2126 | pr_info("mds%d reconnect denied\n", session->s_mds); | 2126 | pr_info("mds%d reconnect denied\n", session->s_mds); |
2127 | remove_session_caps(session); | 2127 | remove_session_caps(session); |
2128 | wake = 1; /* for good measure */ | 2128 | wake = 1; /* for good measure */ |
2129 | complete(&mdsc->session_close_waiters); | 2129 | complete_all(&mdsc->session_close_waiters); |
2130 | kick_requests(mdsc, mds); | 2130 | kick_requests(mdsc, mds); |
2131 | break; | 2131 | break; |
2132 | 2132 | ||
diff --git a/fs/ceph/mon_client.c b/fs/ceph/mon_client.c index cc115eafae11..54fe01c50706 100644 --- a/fs/ceph/mon_client.c +++ b/fs/ceph/mon_client.c | |||
@@ -345,7 +345,7 @@ static void ceph_monc_handle_map(struct ceph_mon_client *monc, | |||
345 | 345 | ||
346 | out: | 346 | out: |
347 | mutex_unlock(&monc->mutex); | 347 | mutex_unlock(&monc->mutex); |
348 | wake_up(&client->auth_wq); | 348 | wake_up_all(&client->auth_wq); |
349 | } | 349 | } |
350 | 350 | ||
351 | /* | 351 | /* |
@@ -462,7 +462,7 @@ static void handle_statfs_reply(struct ceph_mon_client *monc, | |||
462 | } | 462 | } |
463 | mutex_unlock(&monc->mutex); | 463 | mutex_unlock(&monc->mutex); |
464 | if (req) { | 464 | if (req) { |
465 | complete(&req->completion); | 465 | complete_all(&req->completion); |
466 | put_generic_request(req); | 466 | put_generic_request(req); |
467 | } | 467 | } |
468 | return; | 468 | return; |
@@ -718,7 +718,7 @@ static void handle_auth_reply(struct ceph_mon_client *monc, | |||
718 | monc->m_auth->front_max); | 718 | monc->m_auth->front_max); |
719 | if (ret < 0) { | 719 | if (ret < 0) { |
720 | monc->client->auth_err = ret; | 720 | monc->client->auth_err = ret; |
721 | wake_up(&monc->client->auth_wq); | 721 | wake_up_all(&monc->client->auth_wq); |
722 | } else if (ret > 0) { | 722 | } else if (ret > 0) { |
723 | __send_prepared_auth_request(monc, ret); | 723 | __send_prepared_auth_request(monc, ret); |
724 | } else if (!was_auth && monc->auth->ops->is_authenticated(monc->auth)) { | 724 | } else if (!was_auth && monc->auth->ops->is_authenticated(monc->auth)) { |
diff --git a/fs/ceph/osd_client.c b/fs/ceph/osd_client.c index 92b7251a53f1..e38522347898 100644 --- a/fs/ceph/osd_client.c +++ b/fs/ceph/osd_client.c | |||
@@ -862,12 +862,12 @@ static void handle_reply(struct ceph_osd_client *osdc, struct ceph_msg *msg, | |||
862 | if (req->r_callback) | 862 | if (req->r_callback) |
863 | req->r_callback(req, msg); | 863 | req->r_callback(req, msg); |
864 | else | 864 | else |
865 | complete(&req->r_completion); | 865 | complete_all(&req->r_completion); |
866 | 866 | ||
867 | if (flags & CEPH_OSD_FLAG_ONDISK) { | 867 | if (flags & CEPH_OSD_FLAG_ONDISK) { |
868 | if (req->r_safe_callback) | 868 | if (req->r_safe_callback) |
869 | req->r_safe_callback(req, msg); | 869 | req->r_safe_callback(req, msg); |
870 | complete(&req->r_safe_completion); /* fsync waiter */ | 870 | complete_all(&req->r_safe_completion); /* fsync waiter */ |
871 | } | 871 | } |
872 | 872 | ||
873 | done: | 873 | done: |
@@ -1083,7 +1083,7 @@ done: | |||
1083 | if (newmap) | 1083 | if (newmap) |
1084 | kick_requests(osdc, NULL); | 1084 | kick_requests(osdc, NULL); |
1085 | up_read(&osdc->map_sem); | 1085 | up_read(&osdc->map_sem); |
1086 | wake_up(&osdc->client->auth_wq); | 1086 | wake_up_all(&osdc->client->auth_wq); |
1087 | return; | 1087 | return; |
1088 | 1088 | ||
1089 | bad: | 1089 | bad: |
diff --git a/fs/ceph/osdmap.c b/fs/ceph/osdmap.c index 277f8b339577..416d46adbf87 100644 --- a/fs/ceph/osdmap.c +++ b/fs/ceph/osdmap.c | |||
@@ -831,12 +831,13 @@ struct ceph_osdmap *osdmap_apply_incremental(void **p, void *end, | |||
831 | /* remove any? */ | 831 | /* remove any? */ |
832 | while (rbp && pgid_cmp(rb_entry(rbp, struct ceph_pg_mapping, | 832 | while (rbp && pgid_cmp(rb_entry(rbp, struct ceph_pg_mapping, |
833 | node)->pgid, pgid) <= 0) { | 833 | node)->pgid, pgid) <= 0) { |
834 | struct rb_node *cur = rbp; | 834 | struct ceph_pg_mapping *cur = |
835 | rb_entry(rbp, struct ceph_pg_mapping, node); | ||
836 | |||
835 | rbp = rb_next(rbp); | 837 | rbp = rb_next(rbp); |
836 | dout(" removed pg_temp %llx\n", | 838 | dout(" removed pg_temp %llx\n", *(u64 *)&cur->pgid); |
837 | *(u64 *)&rb_entry(cur, struct ceph_pg_mapping, | 839 | rb_erase(&cur->node, &map->pg_temp); |
838 | node)->pgid); | 840 | kfree(cur); |
839 | rb_erase(cur, &map->pg_temp); | ||
840 | } | 841 | } |
841 | 842 | ||
842 | if (pglen) { | 843 | if (pglen) { |
@@ -852,19 +853,22 @@ struct ceph_osdmap *osdmap_apply_incremental(void **p, void *end, | |||
852 | for (j = 0; j < pglen; j++) | 853 | for (j = 0; j < pglen; j++) |
853 | pg->osds[j] = ceph_decode_32(p); | 854 | pg->osds[j] = ceph_decode_32(p); |
854 | err = __insert_pg_mapping(pg, &map->pg_temp); | 855 | err = __insert_pg_mapping(pg, &map->pg_temp); |
855 | if (err) | 856 | if (err) { |
857 | kfree(pg); | ||
856 | goto bad; | 858 | goto bad; |
859 | } | ||
857 | dout(" added pg_temp %llx len %d\n", *(u64 *)&pgid, | 860 | dout(" added pg_temp %llx len %d\n", *(u64 *)&pgid, |
858 | pglen); | 861 | pglen); |
859 | } | 862 | } |
860 | } | 863 | } |
861 | while (rbp) { | 864 | while (rbp) { |
862 | struct rb_node *cur = rbp; | 865 | struct ceph_pg_mapping *cur = |
866 | rb_entry(rbp, struct ceph_pg_mapping, node); | ||
867 | |||
863 | rbp = rb_next(rbp); | 868 | rbp = rb_next(rbp); |
864 | dout(" removed pg_temp %llx\n", | 869 | dout(" removed pg_temp %llx\n", *(u64 *)&cur->pgid); |
865 | *(u64 *)&rb_entry(cur, struct ceph_pg_mapping, | 870 | rb_erase(&cur->node, &map->pg_temp); |
866 | node)->pgid); | 871 | kfree(cur); |
867 | rb_erase(cur, &map->pg_temp); | ||
868 | } | 872 | } |
869 | 873 | ||
870 | /* ignore the rest */ | 874 | /* ignore the rest */ |
diff --git a/fs/cifs/dns_resolve.c b/fs/cifs/dns_resolve.c index 49315cbf742d..853a968e82d7 100644 --- a/fs/cifs/dns_resolve.c +++ b/fs/cifs/dns_resolve.c | |||
@@ -227,7 +227,7 @@ failed_put_cred: | |||
227 | return ret; | 227 | return ret; |
228 | } | 228 | } |
229 | 229 | ||
230 | void __exit cifs_exit_dns_resolver(void) | 230 | void cifs_exit_dns_resolver(void) |
231 | { | 231 | { |
232 | key_revoke(dns_resolver_cache->thread_keyring); | 232 | key_revoke(dns_resolver_cache->thread_keyring); |
233 | unregister_key_type(&key_type_dns_resolver); | 233 | unregister_key_type(&key_type_dns_resolver); |
diff --git a/fs/cifs/dns_resolve.h b/fs/cifs/dns_resolve.h index 26b9eaa9f5ee..5d7f291df162 100644 --- a/fs/cifs/dns_resolve.h +++ b/fs/cifs/dns_resolve.h | |||
@@ -25,7 +25,7 @@ | |||
25 | 25 | ||
26 | #ifdef __KERNEL__ | 26 | #ifdef __KERNEL__ |
27 | extern int __init cifs_init_dns_resolver(void); | 27 | extern int __init cifs_init_dns_resolver(void); |
28 | extern void __exit cifs_exit_dns_resolver(void); | 28 | extern void cifs_exit_dns_resolver(void); |
29 | extern int dns_resolve_server_name_to_ip(const char *unc, char **ip_addr); | 29 | extern int dns_resolve_server_name_to_ip(const char *unc, char **ip_addr); |
30 | #endif /* KERNEL */ | 30 | #endif /* KERNEL */ |
31 | 31 | ||
diff --git a/fs/ecryptfs/messaging.c b/fs/ecryptfs/messaging.c index 2d8dbce9d485..46c4dd8dfcc3 100644 --- a/fs/ecryptfs/messaging.c +++ b/fs/ecryptfs/messaging.c | |||
@@ -31,9 +31,9 @@ static struct mutex ecryptfs_msg_ctx_lists_mux; | |||
31 | 31 | ||
32 | static struct hlist_head *ecryptfs_daemon_hash; | 32 | static struct hlist_head *ecryptfs_daemon_hash; |
33 | struct mutex ecryptfs_daemon_hash_mux; | 33 | struct mutex ecryptfs_daemon_hash_mux; |
34 | static int ecryptfs_hash_buckets; | 34 | static int ecryptfs_hash_bits; |
35 | #define ecryptfs_uid_hash(uid) \ | 35 | #define ecryptfs_uid_hash(uid) \ |
36 | hash_long((unsigned long)uid, ecryptfs_hash_buckets) | 36 | hash_long((unsigned long)uid, ecryptfs_hash_bits) |
37 | 37 | ||
38 | static u32 ecryptfs_msg_counter; | 38 | static u32 ecryptfs_msg_counter; |
39 | static struct ecryptfs_msg_ctx *ecryptfs_msg_ctx_arr; | 39 | static struct ecryptfs_msg_ctx *ecryptfs_msg_ctx_arr; |
@@ -486,18 +486,19 @@ int ecryptfs_init_messaging(void) | |||
486 | } | 486 | } |
487 | mutex_init(&ecryptfs_daemon_hash_mux); | 487 | mutex_init(&ecryptfs_daemon_hash_mux); |
488 | mutex_lock(&ecryptfs_daemon_hash_mux); | 488 | mutex_lock(&ecryptfs_daemon_hash_mux); |
489 | ecryptfs_hash_buckets = 1; | 489 | ecryptfs_hash_bits = 1; |
490 | while (ecryptfs_number_of_users >> ecryptfs_hash_buckets) | 490 | while (ecryptfs_number_of_users >> ecryptfs_hash_bits) |
491 | ecryptfs_hash_buckets++; | 491 | ecryptfs_hash_bits++; |
492 | ecryptfs_daemon_hash = kmalloc((sizeof(struct hlist_head) | 492 | ecryptfs_daemon_hash = kmalloc((sizeof(struct hlist_head) |
493 | * ecryptfs_hash_buckets), GFP_KERNEL); | 493 | * (1 << ecryptfs_hash_bits)), |
494 | GFP_KERNEL); | ||
494 | if (!ecryptfs_daemon_hash) { | 495 | if (!ecryptfs_daemon_hash) { |
495 | rc = -ENOMEM; | 496 | rc = -ENOMEM; |
496 | printk(KERN_ERR "%s: Failed to allocate memory\n", __func__); | 497 | printk(KERN_ERR "%s: Failed to allocate memory\n", __func__); |
497 | mutex_unlock(&ecryptfs_daemon_hash_mux); | 498 | mutex_unlock(&ecryptfs_daemon_hash_mux); |
498 | goto out; | 499 | goto out; |
499 | } | 500 | } |
500 | for (i = 0; i < ecryptfs_hash_buckets; i++) | 501 | for (i = 0; i < (1 << ecryptfs_hash_bits); i++) |
501 | INIT_HLIST_HEAD(&ecryptfs_daemon_hash[i]); | 502 | INIT_HLIST_HEAD(&ecryptfs_daemon_hash[i]); |
502 | mutex_unlock(&ecryptfs_daemon_hash_mux); | 503 | mutex_unlock(&ecryptfs_daemon_hash_mux); |
503 | ecryptfs_msg_ctx_arr = kmalloc((sizeof(struct ecryptfs_msg_ctx) | 504 | ecryptfs_msg_ctx_arr = kmalloc((sizeof(struct ecryptfs_msg_ctx) |
@@ -554,7 +555,7 @@ void ecryptfs_release_messaging(void) | |||
554 | int i; | 555 | int i; |
555 | 556 | ||
556 | mutex_lock(&ecryptfs_daemon_hash_mux); | 557 | mutex_lock(&ecryptfs_daemon_hash_mux); |
557 | for (i = 0; i < ecryptfs_hash_buckets; i++) { | 558 | for (i = 0; i < (1 << ecryptfs_hash_bits); i++) { |
558 | int rc; | 559 | int rc; |
559 | 560 | ||
560 | hlist_for_each_entry(daemon, elem, | 561 | hlist_for_each_entry(daemon, elem, |
diff --git a/fs/gfs2/dir.c b/fs/gfs2/dir.c index 26ca3361a8bc..6b48d7c268b2 100644 --- a/fs/gfs2/dir.c +++ b/fs/gfs2/dir.c | |||
@@ -1231,6 +1231,25 @@ static int do_filldir_main(struct gfs2_inode *dip, u64 *offset, | |||
1231 | return 0; | 1231 | return 0; |
1232 | } | 1232 | } |
1233 | 1233 | ||
1234 | static void *gfs2_alloc_sort_buffer(unsigned size) | ||
1235 | { | ||
1236 | void *ptr = NULL; | ||
1237 | |||
1238 | if (size < KMALLOC_MAX_SIZE) | ||
1239 | ptr = kmalloc(size, GFP_NOFS | __GFP_NOWARN); | ||
1240 | if (!ptr) | ||
1241 | ptr = __vmalloc(size, GFP_NOFS, PAGE_KERNEL); | ||
1242 | return ptr; | ||
1243 | } | ||
1244 | |||
1245 | static void gfs2_free_sort_buffer(void *ptr) | ||
1246 | { | ||
1247 | if (is_vmalloc_addr(ptr)) | ||
1248 | vfree(ptr); | ||
1249 | else | ||
1250 | kfree(ptr); | ||
1251 | } | ||
1252 | |||
1234 | static int gfs2_dir_read_leaf(struct inode *inode, u64 *offset, void *opaque, | 1253 | static int gfs2_dir_read_leaf(struct inode *inode, u64 *offset, void *opaque, |
1235 | filldir_t filldir, int *copied, unsigned *depth, | 1254 | filldir_t filldir, int *copied, unsigned *depth, |
1236 | u64 leaf_no) | 1255 | u64 leaf_no) |
@@ -1271,7 +1290,7 @@ static int gfs2_dir_read_leaf(struct inode *inode, u64 *offset, void *opaque, | |||
1271 | * 99 is the maximum number of entries that can fit in a single | 1290 | * 99 is the maximum number of entries that can fit in a single |
1272 | * leaf block. | 1291 | * leaf block. |
1273 | */ | 1292 | */ |
1274 | larr = vmalloc((leaves + entries + 99) * sizeof(void *)); | 1293 | larr = gfs2_alloc_sort_buffer((leaves + entries + 99) * sizeof(void *)); |
1275 | if (!larr) | 1294 | if (!larr) |
1276 | goto out; | 1295 | goto out; |
1277 | darr = (const struct gfs2_dirent **)(larr + leaves); | 1296 | darr = (const struct gfs2_dirent **)(larr + leaves); |
@@ -1282,7 +1301,7 @@ static int gfs2_dir_read_leaf(struct inode *inode, u64 *offset, void *opaque, | |||
1282 | do { | 1301 | do { |
1283 | error = get_leaf(ip, lfn, &bh); | 1302 | error = get_leaf(ip, lfn, &bh); |
1284 | if (error) | 1303 | if (error) |
1285 | goto out_kfree; | 1304 | goto out_free; |
1286 | lf = (struct gfs2_leaf *)bh->b_data; | 1305 | lf = (struct gfs2_leaf *)bh->b_data; |
1287 | lfn = be64_to_cpu(lf->lf_next); | 1306 | lfn = be64_to_cpu(lf->lf_next); |
1288 | if (lf->lf_entries) { | 1307 | if (lf->lf_entries) { |
@@ -1291,7 +1310,7 @@ static int gfs2_dir_read_leaf(struct inode *inode, u64 *offset, void *opaque, | |||
1291 | gfs2_dirent_gather, NULL, &g); | 1310 | gfs2_dirent_gather, NULL, &g); |
1292 | error = PTR_ERR(dent); | 1311 | error = PTR_ERR(dent); |
1293 | if (IS_ERR(dent)) | 1312 | if (IS_ERR(dent)) |
1294 | goto out_kfree; | 1313 | goto out_free; |
1295 | if (entries2 != g.offset) { | 1314 | if (entries2 != g.offset) { |
1296 | fs_warn(sdp, "Number of entries corrupt in dir " | 1315 | fs_warn(sdp, "Number of entries corrupt in dir " |
1297 | "leaf %llu, entries2 (%u) != " | 1316 | "leaf %llu, entries2 (%u) != " |
@@ -1300,7 +1319,7 @@ static int gfs2_dir_read_leaf(struct inode *inode, u64 *offset, void *opaque, | |||
1300 | entries2, g.offset); | 1319 | entries2, g.offset); |
1301 | 1320 | ||
1302 | error = -EIO; | 1321 | error = -EIO; |
1303 | goto out_kfree; | 1322 | goto out_free; |
1304 | } | 1323 | } |
1305 | error = 0; | 1324 | error = 0; |
1306 | larr[leaf++] = bh; | 1325 | larr[leaf++] = bh; |
@@ -1312,10 +1331,10 @@ static int gfs2_dir_read_leaf(struct inode *inode, u64 *offset, void *opaque, | |||
1312 | BUG_ON(entries2 != entries); | 1331 | BUG_ON(entries2 != entries); |
1313 | error = do_filldir_main(ip, offset, opaque, filldir, darr, | 1332 | error = do_filldir_main(ip, offset, opaque, filldir, darr, |
1314 | entries, copied); | 1333 | entries, copied); |
1315 | out_kfree: | 1334 | out_free: |
1316 | for(i = 0; i < leaf; i++) | 1335 | for(i = 0; i < leaf; i++) |
1317 | brelse(larr[i]); | 1336 | brelse(larr[i]); |
1318 | vfree(larr); | 1337 | gfs2_free_sort_buffer(larr); |
1319 | out: | 1338 | out: |
1320 | return error; | 1339 | return error; |
1321 | } | 1340 | } |
diff --git a/fs/nfs/file.c b/fs/nfs/file.c index 36a5e74f51b4..f036153d9f50 100644 --- a/fs/nfs/file.c +++ b/fs/nfs/file.c | |||
@@ -27,6 +27,7 @@ | |||
27 | #include <linux/pagemap.h> | 27 | #include <linux/pagemap.h> |
28 | #include <linux/aio.h> | 28 | #include <linux/aio.h> |
29 | #include <linux/gfp.h> | 29 | #include <linux/gfp.h> |
30 | #include <linux/swap.h> | ||
30 | 31 | ||
31 | #include <asm/uaccess.h> | 32 | #include <asm/uaccess.h> |
32 | #include <asm/system.h> | 33 | #include <asm/system.h> |
@@ -493,11 +494,19 @@ static void nfs_invalidate_page(struct page *page, unsigned long offset) | |||
493 | */ | 494 | */ |
494 | static int nfs_release_page(struct page *page, gfp_t gfp) | 495 | static int nfs_release_page(struct page *page, gfp_t gfp) |
495 | { | 496 | { |
497 | struct address_space *mapping = page->mapping; | ||
498 | |||
496 | dfprintk(PAGECACHE, "NFS: release_page(%p)\n", page); | 499 | dfprintk(PAGECACHE, "NFS: release_page(%p)\n", page); |
497 | 500 | ||
498 | /* Only do I/O if gfp is a superset of GFP_KERNEL */ | 501 | /* Only do I/O if gfp is a superset of GFP_KERNEL */ |
499 | if ((gfp & GFP_KERNEL) == GFP_KERNEL) | 502 | if (mapping && (gfp & GFP_KERNEL) == GFP_KERNEL) { |
500 | nfs_wb_page(page->mapping->host, page); | 503 | int how = FLUSH_SYNC; |
504 | |||
505 | /* Don't let kswapd deadlock waiting for OOM RPC calls */ | ||
506 | if (current_is_kswapd()) | ||
507 | how = 0; | ||
508 | nfs_commit_inode(mapping->host, how); | ||
509 | } | ||
501 | /* If PagePrivate() is set, then the page is not freeable */ | 510 | /* If PagePrivate() is set, then the page is not freeable */ |
502 | if (PagePrivate(page)) | 511 | if (PagePrivate(page)) |
503 | return 0; | 512 | return 0; |
diff --git a/fs/nfs/nfsroot.c b/fs/nfs/nfsroot.c index 6bd19d843af7..df101d9f546a 100644 --- a/fs/nfs/nfsroot.c +++ b/fs/nfs/nfsroot.c | |||
@@ -105,7 +105,7 @@ static char nfs_root_name[256] __initdata = ""; | |||
105 | static __be32 servaddr __initdata = 0; | 105 | static __be32 servaddr __initdata = 0; |
106 | 106 | ||
107 | /* Name of directory to mount */ | 107 | /* Name of directory to mount */ |
108 | static char nfs_export_path[NFS_MAXPATHLEN] __initdata = { 0, }; | 108 | static char nfs_export_path[NFS_MAXPATHLEN + 1] __initdata = { 0, }; |
109 | 109 | ||
110 | /* NFS-related data */ | 110 | /* NFS-related data */ |
111 | static struct nfs_mount_data nfs_data __initdata = { 0, };/* NFS mount info */ | 111 | static struct nfs_mount_data nfs_data __initdata = { 0, };/* NFS mount info */ |
diff --git a/fs/nfs/write.c b/fs/nfs/write.c index 91679e2631ee..9f81bdd91c55 100644 --- a/fs/nfs/write.c +++ b/fs/nfs/write.c | |||
@@ -222,7 +222,7 @@ static void nfs_end_page_writeback(struct page *page) | |||
222 | clear_bdi_congested(&nfss->backing_dev_info, BLK_RW_ASYNC); | 222 | clear_bdi_congested(&nfss->backing_dev_info, BLK_RW_ASYNC); |
223 | } | 223 | } |
224 | 224 | ||
225 | static struct nfs_page *nfs_find_and_lock_request(struct page *page) | 225 | static struct nfs_page *nfs_find_and_lock_request(struct page *page, bool nonblock) |
226 | { | 226 | { |
227 | struct inode *inode = page->mapping->host; | 227 | struct inode *inode = page->mapping->host; |
228 | struct nfs_page *req; | 228 | struct nfs_page *req; |
@@ -241,7 +241,10 @@ static struct nfs_page *nfs_find_and_lock_request(struct page *page) | |||
241 | * request as dirty (in which case we don't care). | 241 | * request as dirty (in which case we don't care). |
242 | */ | 242 | */ |
243 | spin_unlock(&inode->i_lock); | 243 | spin_unlock(&inode->i_lock); |
244 | ret = nfs_wait_on_request(req); | 244 | if (!nonblock) |
245 | ret = nfs_wait_on_request(req); | ||
246 | else | ||
247 | ret = -EAGAIN; | ||
245 | nfs_release_request(req); | 248 | nfs_release_request(req); |
246 | if (ret != 0) | 249 | if (ret != 0) |
247 | return ERR_PTR(ret); | 250 | return ERR_PTR(ret); |
@@ -256,12 +259,12 @@ static struct nfs_page *nfs_find_and_lock_request(struct page *page) | |||
256 | * May return an error if the user signalled nfs_wait_on_request(). | 259 | * May return an error if the user signalled nfs_wait_on_request(). |
257 | */ | 260 | */ |
258 | static int nfs_page_async_flush(struct nfs_pageio_descriptor *pgio, | 261 | static int nfs_page_async_flush(struct nfs_pageio_descriptor *pgio, |
259 | struct page *page) | 262 | struct page *page, bool nonblock) |
260 | { | 263 | { |
261 | struct nfs_page *req; | 264 | struct nfs_page *req; |
262 | int ret = 0; | 265 | int ret = 0; |
263 | 266 | ||
264 | req = nfs_find_and_lock_request(page); | 267 | req = nfs_find_and_lock_request(page, nonblock); |
265 | if (!req) | 268 | if (!req) |
266 | goto out; | 269 | goto out; |
267 | ret = PTR_ERR(req); | 270 | ret = PTR_ERR(req); |
@@ -283,12 +286,20 @@ out: | |||
283 | static int nfs_do_writepage(struct page *page, struct writeback_control *wbc, struct nfs_pageio_descriptor *pgio) | 286 | static int nfs_do_writepage(struct page *page, struct writeback_control *wbc, struct nfs_pageio_descriptor *pgio) |
284 | { | 287 | { |
285 | struct inode *inode = page->mapping->host; | 288 | struct inode *inode = page->mapping->host; |
289 | int ret; | ||
286 | 290 | ||
287 | nfs_inc_stats(inode, NFSIOS_VFSWRITEPAGE); | 291 | nfs_inc_stats(inode, NFSIOS_VFSWRITEPAGE); |
288 | nfs_add_stats(inode, NFSIOS_WRITEPAGES, 1); | 292 | nfs_add_stats(inode, NFSIOS_WRITEPAGES, 1); |
289 | 293 | ||
290 | nfs_pageio_cond_complete(pgio, page->index); | 294 | nfs_pageio_cond_complete(pgio, page->index); |
291 | return nfs_page_async_flush(pgio, page); | 295 | ret = nfs_page_async_flush(pgio, page, |
296 | wbc->sync_mode == WB_SYNC_NONE || | ||
297 | wbc->nonblocking != 0); | ||
298 | if (ret == -EAGAIN) { | ||
299 | redirty_page_for_writepage(wbc, page); | ||
300 | ret = 0; | ||
301 | } | ||
302 | return ret; | ||
292 | } | 303 | } |
293 | 304 | ||
294 | /* | 305 | /* |
@@ -1379,7 +1390,7 @@ static const struct rpc_call_ops nfs_commit_ops = { | |||
1379 | .rpc_release = nfs_commit_release, | 1390 | .rpc_release = nfs_commit_release, |
1380 | }; | 1391 | }; |
1381 | 1392 | ||
1382 | static int nfs_commit_inode(struct inode *inode, int how) | 1393 | int nfs_commit_inode(struct inode *inode, int how) |
1383 | { | 1394 | { |
1384 | LIST_HEAD(head); | 1395 | LIST_HEAD(head); |
1385 | int may_wait = how & FLUSH_SYNC; | 1396 | int may_wait = how & FLUSH_SYNC; |
@@ -1443,11 +1454,6 @@ out_mark_dirty: | |||
1443 | return ret; | 1454 | return ret; |
1444 | } | 1455 | } |
1445 | #else | 1456 | #else |
1446 | static int nfs_commit_inode(struct inode *inode, int how) | ||
1447 | { | ||
1448 | return 0; | ||
1449 | } | ||
1450 | |||
1451 | static int nfs_commit_unstable_pages(struct inode *inode, struct writeback_control *wbc) | 1457 | static int nfs_commit_unstable_pages(struct inode *inode, struct writeback_control *wbc) |
1452 | { | 1458 | { |
1453 | return 0; | 1459 | return 0; |
@@ -1546,7 +1552,7 @@ int nfs_migrate_page(struct address_space *mapping, struct page *newpage, | |||
1546 | 1552 | ||
1547 | nfs_fscache_release_page(page, GFP_KERNEL); | 1553 | nfs_fscache_release_page(page, GFP_KERNEL); |
1548 | 1554 | ||
1549 | req = nfs_find_and_lock_request(page); | 1555 | req = nfs_find_and_lock_request(page, false); |
1550 | ret = PTR_ERR(req); | 1556 | ret = PTR_ERR(req); |
1551 | if (IS_ERR(req)) | 1557 | if (IS_ERR(req)) |
1552 | goto out; | 1558 | goto out; |
diff --git a/fs/proc/array.c b/fs/proc/array.c index 9b58d38bc911..fff6572676ae 100644 --- a/fs/proc/array.c +++ b/fs/proc/array.c | |||
@@ -176,7 +176,7 @@ static inline void task_state(struct seq_file *m, struct pid_namespace *ns, | |||
176 | if (tracer) | 176 | if (tracer) |
177 | tpid = task_pid_nr_ns(tracer, ns); | 177 | tpid = task_pid_nr_ns(tracer, ns); |
178 | } | 178 | } |
179 | cred = get_cred((struct cred *) __task_cred(p)); | 179 | cred = get_task_cred(p); |
180 | seq_printf(m, | 180 | seq_printf(m, |
181 | "State:\t%s\n" | 181 | "State:\t%s\n" |
182 | "Tgid:\t%d\n" | 182 | "Tgid:\t%d\n" |
diff --git a/fs/sysfs/symlink.c b/fs/sysfs/symlink.c index f71246bebfe4..a7ac78f8e67a 100644 --- a/fs/sysfs/symlink.c +++ b/fs/sysfs/symlink.c | |||
@@ -28,6 +28,7 @@ static int sysfs_do_create_link(struct kobject *kobj, struct kobject *target, | |||
28 | struct sysfs_dirent *target_sd = NULL; | 28 | struct sysfs_dirent *target_sd = NULL; |
29 | struct sysfs_dirent *sd = NULL; | 29 | struct sysfs_dirent *sd = NULL; |
30 | struct sysfs_addrm_cxt acxt; | 30 | struct sysfs_addrm_cxt acxt; |
31 | enum kobj_ns_type ns_type; | ||
31 | int error; | 32 | int error; |
32 | 33 | ||
33 | BUG_ON(!name); | 34 | BUG_ON(!name); |
@@ -58,16 +59,29 @@ static int sysfs_do_create_link(struct kobject *kobj, struct kobject *target, | |||
58 | if (!sd) | 59 | if (!sd) |
59 | goto out_put; | 60 | goto out_put; |
60 | 61 | ||
61 | if (sysfs_ns_type(parent_sd)) | 62 | ns_type = sysfs_ns_type(parent_sd); |
63 | if (ns_type) | ||
62 | sd->s_ns = target->ktype->namespace(target); | 64 | sd->s_ns = target->ktype->namespace(target); |
63 | sd->s_symlink.target_sd = target_sd; | 65 | sd->s_symlink.target_sd = target_sd; |
64 | target_sd = NULL; /* reference is now owned by the symlink */ | 66 | target_sd = NULL; /* reference is now owned by the symlink */ |
65 | 67 | ||
66 | sysfs_addrm_start(&acxt, parent_sd); | 68 | sysfs_addrm_start(&acxt, parent_sd); |
67 | if (warn) | 69 | /* Symlinks must be between directories with the same ns_type */ |
68 | error = sysfs_add_one(&acxt, sd); | 70 | if (!ns_type || |
69 | else | 71 | (ns_type == sysfs_ns_type(sd->s_symlink.target_sd->s_parent))) { |
70 | error = __sysfs_add_one(&acxt, sd); | 72 | if (warn) |
73 | error = sysfs_add_one(&acxt, sd); | ||
74 | else | ||
75 | error = __sysfs_add_one(&acxt, sd); | ||
76 | } else { | ||
77 | error = -EINVAL; | ||
78 | WARN(1, KERN_WARNING | ||
79 | "sysfs: symlink across ns_types %s/%s -> %s/%s\n", | ||
80 | parent_sd->s_name, | ||
81 | sd->s_name, | ||
82 | sd->s_symlink.target_sd->s_parent->s_name, | ||
83 | sd->s_symlink.target_sd->s_name); | ||
84 | } | ||
71 | sysfs_addrm_finish(&acxt); | 85 | sysfs_addrm_finish(&acxt); |
72 | 86 | ||
73 | if (error) | 87 | if (error) |
@@ -122,7 +136,7 @@ void sysfs_delete_link(struct kobject *kobj, struct kobject *targ, | |||
122 | { | 136 | { |
123 | const void *ns = NULL; | 137 | const void *ns = NULL; |
124 | spin_lock(&sysfs_assoc_lock); | 138 | spin_lock(&sysfs_assoc_lock); |
125 | if (targ->sd) | 139 | if (targ->sd && sysfs_ns_type(kobj->sd)) |
126 | ns = targ->sd->s_ns; | 140 | ns = targ->sd->s_ns; |
127 | spin_unlock(&sysfs_assoc_lock); | 141 | spin_unlock(&sysfs_assoc_lock); |
128 | sysfs_hash_and_remove(kobj->sd, ns, name); | 142 | sysfs_hash_and_remove(kobj->sd, ns, name); |