diff options
Diffstat (limited to 'fs')
-rw-r--r-- | fs/ceph/caps.c | 4 | ||||
-rw-r--r-- | fs/ceph/dir.c | 4 | ||||
-rw-r--r-- | fs/ceph/mds_client.c | 10 | ||||
-rw-r--r-- | fs/ceph/mds_client.h | 7 | ||||
-rw-r--r-- | fs/ceph/xattr.c | 4 | ||||
-rw-r--r-- | fs/logfs/dev_mtd.c | 6 | ||||
-rw-r--r-- | fs/nfs/nfs4proc.c | 115 | ||||
-rw-r--r-- | fs/nfs/nfs4state.c | 2 | ||||
-rw-r--r-- | fs/nfs/nfs4xdr.c | 5 | ||||
-rw-r--r-- | fs/proc/base.c | 126 |
10 files changed, 117 insertions, 166 deletions
diff --git a/fs/ceph/caps.c b/fs/ceph/caps.c index b60fc8bfb3e9..620daad201db 100644 --- a/fs/ceph/caps.c +++ b/fs/ceph/caps.c | |||
@@ -641,10 +641,10 @@ static int __cap_is_valid(struct ceph_cap *cap) | |||
641 | unsigned long ttl; | 641 | unsigned long ttl; |
642 | u32 gen; | 642 | u32 gen; |
643 | 643 | ||
644 | spin_lock(&cap->session->s_cap_lock); | 644 | spin_lock(&cap->session->s_gen_ttl_lock); |
645 | gen = cap->session->s_cap_gen; | 645 | gen = cap->session->s_cap_gen; |
646 | ttl = cap->session->s_cap_ttl; | 646 | ttl = cap->session->s_cap_ttl; |
647 | spin_unlock(&cap->session->s_cap_lock); | 647 | spin_unlock(&cap->session->s_gen_ttl_lock); |
648 | 648 | ||
649 | if (cap->cap_gen < gen || time_after_eq(jiffies, ttl)) { | 649 | if (cap->cap_gen < gen || time_after_eq(jiffies, ttl)) { |
650 | dout("__cap_is_valid %p cap %p issued %s " | 650 | dout("__cap_is_valid %p cap %p issued %s " |
diff --git a/fs/ceph/dir.c b/fs/ceph/dir.c index 618246bc2196..3e8094be4604 100644 --- a/fs/ceph/dir.c +++ b/fs/ceph/dir.c | |||
@@ -975,10 +975,10 @@ static int dentry_lease_is_valid(struct dentry *dentry) | |||
975 | di = ceph_dentry(dentry); | 975 | di = ceph_dentry(dentry); |
976 | if (di->lease_session) { | 976 | if (di->lease_session) { |
977 | s = di->lease_session; | 977 | s = di->lease_session; |
978 | spin_lock(&s->s_cap_lock); | 978 | spin_lock(&s->s_gen_ttl_lock); |
979 | gen = s->s_cap_gen; | 979 | gen = s->s_cap_gen; |
980 | ttl = s->s_cap_ttl; | 980 | ttl = s->s_cap_ttl; |
981 | spin_unlock(&s->s_cap_lock); | 981 | spin_unlock(&s->s_gen_ttl_lock); |
982 | 982 | ||
983 | if (di->lease_gen == gen && | 983 | if (di->lease_gen == gen && |
984 | time_before(jiffies, dentry->d_time) && | 984 | time_before(jiffies, dentry->d_time) && |
diff --git a/fs/ceph/mds_client.c b/fs/ceph/mds_client.c index 23ab6a3f1825..866e8d7ca37d 100644 --- a/fs/ceph/mds_client.c +++ b/fs/ceph/mds_client.c | |||
@@ -262,6 +262,7 @@ static int parse_reply_info(struct ceph_msg *msg, | |||
262 | /* trace */ | 262 | /* trace */ |
263 | ceph_decode_32_safe(&p, end, len, bad); | 263 | ceph_decode_32_safe(&p, end, len, bad); |
264 | if (len > 0) { | 264 | if (len > 0) { |
265 | ceph_decode_need(&p, end, len, bad); | ||
265 | err = parse_reply_info_trace(&p, p+len, info, features); | 266 | err = parse_reply_info_trace(&p, p+len, info, features); |
266 | if (err < 0) | 267 | if (err < 0) |
267 | goto out_bad; | 268 | goto out_bad; |
@@ -270,6 +271,7 @@ static int parse_reply_info(struct ceph_msg *msg, | |||
270 | /* extra */ | 271 | /* extra */ |
271 | ceph_decode_32_safe(&p, end, len, bad); | 272 | ceph_decode_32_safe(&p, end, len, bad); |
272 | if (len > 0) { | 273 | if (len > 0) { |
274 | ceph_decode_need(&p, end, len, bad); | ||
273 | err = parse_reply_info_extra(&p, p+len, info, features); | 275 | err = parse_reply_info_extra(&p, p+len, info, features); |
274 | if (err < 0) | 276 | if (err < 0) |
275 | goto out_bad; | 277 | goto out_bad; |
@@ -398,9 +400,11 @@ static struct ceph_mds_session *register_session(struct ceph_mds_client *mdsc, | |||
398 | s->s_con.peer_name.type = CEPH_ENTITY_TYPE_MDS; | 400 | s->s_con.peer_name.type = CEPH_ENTITY_TYPE_MDS; |
399 | s->s_con.peer_name.num = cpu_to_le64(mds); | 401 | s->s_con.peer_name.num = cpu_to_le64(mds); |
400 | 402 | ||
401 | spin_lock_init(&s->s_cap_lock); | 403 | spin_lock_init(&s->s_gen_ttl_lock); |
402 | s->s_cap_gen = 0; | 404 | s->s_cap_gen = 0; |
403 | s->s_cap_ttl = 0; | 405 | s->s_cap_ttl = 0; |
406 | |||
407 | spin_lock_init(&s->s_cap_lock); | ||
404 | s->s_renew_requested = 0; | 408 | s->s_renew_requested = 0; |
405 | s->s_renew_seq = 0; | 409 | s->s_renew_seq = 0; |
406 | INIT_LIST_HEAD(&s->s_caps); | 410 | INIT_LIST_HEAD(&s->s_caps); |
@@ -2326,10 +2330,10 @@ static void handle_session(struct ceph_mds_session *session, | |||
2326 | case CEPH_SESSION_STALE: | 2330 | case CEPH_SESSION_STALE: |
2327 | pr_info("mds%d caps went stale, renewing\n", | 2331 | pr_info("mds%d caps went stale, renewing\n", |
2328 | session->s_mds); | 2332 | session->s_mds); |
2329 | spin_lock(&session->s_cap_lock); | 2333 | spin_lock(&session->s_gen_ttl_lock); |
2330 | session->s_cap_gen++; | 2334 | session->s_cap_gen++; |
2331 | session->s_cap_ttl = 0; | 2335 | session->s_cap_ttl = 0; |
2332 | spin_unlock(&session->s_cap_lock); | 2336 | spin_unlock(&session->s_gen_ttl_lock); |
2333 | send_renew_caps(mdsc, session); | 2337 | send_renew_caps(mdsc, session); |
2334 | break; | 2338 | break; |
2335 | 2339 | ||
diff --git a/fs/ceph/mds_client.h b/fs/ceph/mds_client.h index a50ca0e39475..8c7c04ebb595 100644 --- a/fs/ceph/mds_client.h +++ b/fs/ceph/mds_client.h | |||
@@ -117,10 +117,13 @@ struct ceph_mds_session { | |||
117 | void *s_authorizer_buf, *s_authorizer_reply_buf; | 117 | void *s_authorizer_buf, *s_authorizer_reply_buf; |
118 | size_t s_authorizer_buf_len, s_authorizer_reply_buf_len; | 118 | size_t s_authorizer_buf_len, s_authorizer_reply_buf_len; |
119 | 119 | ||
120 | /* protected by s_cap_lock */ | 120 | /* protected by s_gen_ttl_lock */ |
121 | spinlock_t s_cap_lock; | 121 | spinlock_t s_gen_ttl_lock; |
122 | u32 s_cap_gen; /* inc each time we get mds stale msg */ | 122 | u32 s_cap_gen; /* inc each time we get mds stale msg */ |
123 | unsigned long s_cap_ttl; /* when session caps expire */ | 123 | unsigned long s_cap_ttl; /* when session caps expire */ |
124 | |||
125 | /* protected by s_cap_lock */ | ||
126 | spinlock_t s_cap_lock; | ||
124 | struct list_head s_caps; /* all caps issued by this session */ | 127 | struct list_head s_caps; /* all caps issued by this session */ |
125 | int s_nr_caps, s_trim_caps; | 128 | int s_nr_caps, s_trim_caps; |
126 | int s_num_cap_releases; | 129 | int s_num_cap_releases; |
diff --git a/fs/ceph/xattr.c b/fs/ceph/xattr.c index 857214ae8c08..a76f697303d9 100644 --- a/fs/ceph/xattr.c +++ b/fs/ceph/xattr.c | |||
@@ -111,8 +111,10 @@ static size_t ceph_vxattrcb_layout(struct ceph_inode_info *ci, char *val, | |||
111 | } | 111 | } |
112 | 112 | ||
113 | static struct ceph_vxattr_cb ceph_file_vxattrs[] = { | 113 | static struct ceph_vxattr_cb ceph_file_vxattrs[] = { |
114 | { true, "ceph.file.layout", ceph_vxattrcb_layout}, | ||
115 | /* The following extended attribute name is deprecated */ | ||
114 | { true, "ceph.layout", ceph_vxattrcb_layout}, | 116 | { true, "ceph.layout", ceph_vxattrcb_layout}, |
115 | { NULL, NULL } | 117 | { true, NULL, NULL } |
116 | }; | 118 | }; |
117 | 119 | ||
118 | static struct ceph_vxattr_cb *ceph_inode_vxattrs(struct inode *inode) | 120 | static struct ceph_vxattr_cb *ceph_inode_vxattrs(struct inode *inode) |
diff --git a/fs/logfs/dev_mtd.c b/fs/logfs/dev_mtd.c index e97404d611e0..9c501449450d 100644 --- a/fs/logfs/dev_mtd.c +++ b/fs/logfs/dev_mtd.c | |||
@@ -152,9 +152,6 @@ static struct page *logfs_mtd_find_first_sb(struct super_block *sb, u64 *ofs) | |||
152 | filler_t *filler = logfs_mtd_readpage; | 152 | filler_t *filler = logfs_mtd_readpage; |
153 | struct mtd_info *mtd = super->s_mtd; | 153 | struct mtd_info *mtd = super->s_mtd; |
154 | 154 | ||
155 | if (!mtd_can_have_bb(mtd)) | ||
156 | return NULL; | ||
157 | |||
158 | *ofs = 0; | 155 | *ofs = 0; |
159 | while (mtd_block_isbad(mtd, *ofs)) { | 156 | while (mtd_block_isbad(mtd, *ofs)) { |
160 | *ofs += mtd->erasesize; | 157 | *ofs += mtd->erasesize; |
@@ -172,9 +169,6 @@ static struct page *logfs_mtd_find_last_sb(struct super_block *sb, u64 *ofs) | |||
172 | filler_t *filler = logfs_mtd_readpage; | 169 | filler_t *filler = logfs_mtd_readpage; |
173 | struct mtd_info *mtd = super->s_mtd; | 170 | struct mtd_info *mtd = super->s_mtd; |
174 | 171 | ||
175 | if (!mtd_can_have_bb(mtd)) | ||
176 | return NULL; | ||
177 | |||
178 | *ofs = mtd->size - mtd->erasesize; | 172 | *ofs = mtd->size - mtd->erasesize; |
179 | while (mtd_block_isbad(mtd, *ofs)) { | 173 | while (mtd_block_isbad(mtd, *ofs)) { |
180 | *ofs -= mtd->erasesize; | 174 | *ofs -= mtd->erasesize; |
diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index 87b9b91f76cf..ea7adfc868c2 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c | |||
@@ -3621,8 +3621,8 @@ static ssize_t __nfs4_get_acl_uncached(struct inode *inode, void *buf, size_t bu | |||
3621 | } | 3621 | } |
3622 | if (npages > 1) { | 3622 | if (npages > 1) { |
3623 | /* for decoding across pages */ | 3623 | /* for decoding across pages */ |
3624 | args.acl_scratch = alloc_page(GFP_KERNEL); | 3624 | res.acl_scratch = alloc_page(GFP_KERNEL); |
3625 | if (!args.acl_scratch) | 3625 | if (!res.acl_scratch) |
3626 | goto out_free; | 3626 | goto out_free; |
3627 | } | 3627 | } |
3628 | args.acl_len = npages * PAGE_SIZE; | 3628 | args.acl_len = npages * PAGE_SIZE; |
@@ -3658,8 +3658,8 @@ out_free: | |||
3658 | for (i = 0; i < npages; i++) | 3658 | for (i = 0; i < npages; i++) |
3659 | if (pages[i]) | 3659 | if (pages[i]) |
3660 | __free_page(pages[i]); | 3660 | __free_page(pages[i]); |
3661 | if (args.acl_scratch) | 3661 | if (res.acl_scratch) |
3662 | __free_page(args.acl_scratch); | 3662 | __free_page(res.acl_scratch); |
3663 | return ret; | 3663 | return ret; |
3664 | } | 3664 | } |
3665 | 3665 | ||
@@ -5104,37 +5104,53 @@ int nfs4_proc_get_lease_time(struct nfs_client *clp, struct nfs_fsinfo *fsinfo) | |||
5104 | return status; | 5104 | return status; |
5105 | } | 5105 | } |
5106 | 5106 | ||
5107 | static struct nfs4_slot *nfs4_alloc_slots(u32 max_slots, gfp_t gfp_flags) | ||
5108 | { | ||
5109 | return kcalloc(max_slots, sizeof(struct nfs4_slot), gfp_flags); | ||
5110 | } | ||
5111 | |||
5112 | static void nfs4_add_and_init_slots(struct nfs4_slot_table *tbl, | ||
5113 | struct nfs4_slot *new, | ||
5114 | u32 max_slots, | ||
5115 | u32 ivalue) | ||
5116 | { | ||
5117 | struct nfs4_slot *old = NULL; | ||
5118 | u32 i; | ||
5119 | |||
5120 | spin_lock(&tbl->slot_tbl_lock); | ||
5121 | if (new) { | ||
5122 | old = tbl->slots; | ||
5123 | tbl->slots = new; | ||
5124 | tbl->max_slots = max_slots; | ||
5125 | } | ||
5126 | tbl->highest_used_slotid = -1; /* no slot is currently used */ | ||
5127 | for (i = 0; i < tbl->max_slots; i++) | ||
5128 | tbl->slots[i].seq_nr = ivalue; | ||
5129 | spin_unlock(&tbl->slot_tbl_lock); | ||
5130 | kfree(old); | ||
5131 | } | ||
5132 | |||
5107 | /* | 5133 | /* |
5108 | * Reset a slot table | 5134 | * (re)Initialise a slot table |
5109 | */ | 5135 | */ |
5110 | static int nfs4_reset_slot_table(struct nfs4_slot_table *tbl, u32 max_reqs, | 5136 | static int nfs4_realloc_slot_table(struct nfs4_slot_table *tbl, u32 max_reqs, |
5111 | int ivalue) | 5137 | u32 ivalue) |
5112 | { | 5138 | { |
5113 | struct nfs4_slot *new = NULL; | 5139 | struct nfs4_slot *new = NULL; |
5114 | int i; | 5140 | int ret = -ENOMEM; |
5115 | int ret = 0; | ||
5116 | 5141 | ||
5117 | dprintk("--> %s: max_reqs=%u, tbl->max_slots %d\n", __func__, | 5142 | dprintk("--> %s: max_reqs=%u, tbl->max_slots %d\n", __func__, |
5118 | max_reqs, tbl->max_slots); | 5143 | max_reqs, tbl->max_slots); |
5119 | 5144 | ||
5120 | /* Does the newly negotiated max_reqs match the existing slot table? */ | 5145 | /* Does the newly negotiated max_reqs match the existing slot table? */ |
5121 | if (max_reqs != tbl->max_slots) { | 5146 | if (max_reqs != tbl->max_slots) { |
5122 | ret = -ENOMEM; | 5147 | new = nfs4_alloc_slots(max_reqs, GFP_NOFS); |
5123 | new = kmalloc(max_reqs * sizeof(struct nfs4_slot), | ||
5124 | GFP_NOFS); | ||
5125 | if (!new) | 5148 | if (!new) |
5126 | goto out; | 5149 | goto out; |
5127 | ret = 0; | ||
5128 | kfree(tbl->slots); | ||
5129 | } | ||
5130 | spin_lock(&tbl->slot_tbl_lock); | ||
5131 | if (new) { | ||
5132 | tbl->slots = new; | ||
5133 | tbl->max_slots = max_reqs; | ||
5134 | } | 5150 | } |
5135 | for (i = 0; i < tbl->max_slots; ++i) | 5151 | ret = 0; |
5136 | tbl->slots[i].seq_nr = ivalue; | 5152 | |
5137 | spin_unlock(&tbl->slot_tbl_lock); | 5153 | nfs4_add_and_init_slots(tbl, new, max_reqs, ivalue); |
5138 | dprintk("%s: tbl=%p slots=%p max_slots=%d\n", __func__, | 5154 | dprintk("%s: tbl=%p slots=%p max_slots=%d\n", __func__, |
5139 | tbl, tbl->slots, tbl->max_slots); | 5155 | tbl, tbl->slots, tbl->max_slots); |
5140 | out: | 5156 | out: |
@@ -5157,36 +5173,6 @@ static void nfs4_destroy_slot_tables(struct nfs4_session *session) | |||
5157 | } | 5173 | } |
5158 | 5174 | ||
5159 | /* | 5175 | /* |
5160 | * Initialize slot table | ||
5161 | */ | ||
5162 | static int nfs4_init_slot_table(struct nfs4_slot_table *tbl, | ||
5163 | int max_slots, int ivalue) | ||
5164 | { | ||
5165 | struct nfs4_slot *slot; | ||
5166 | int ret = -ENOMEM; | ||
5167 | |||
5168 | BUG_ON(max_slots > NFS4_MAX_SLOT_TABLE); | ||
5169 | |||
5170 | dprintk("--> %s: max_reqs=%u\n", __func__, max_slots); | ||
5171 | |||
5172 | slot = kcalloc(max_slots, sizeof(struct nfs4_slot), GFP_NOFS); | ||
5173 | if (!slot) | ||
5174 | goto out; | ||
5175 | ret = 0; | ||
5176 | |||
5177 | spin_lock(&tbl->slot_tbl_lock); | ||
5178 | tbl->max_slots = max_slots; | ||
5179 | tbl->slots = slot; | ||
5180 | tbl->highest_used_slotid = NFS4_NO_SLOT; /* no slot is currently used */ | ||
5181 | spin_unlock(&tbl->slot_tbl_lock); | ||
5182 | dprintk("%s: tbl=%p slots=%p max_slots=%d\n", __func__, | ||
5183 | tbl, tbl->slots, tbl->max_slots); | ||
5184 | out: | ||
5185 | dprintk("<-- %s: return %d\n", __func__, ret); | ||
5186 | return ret; | ||
5187 | } | ||
5188 | |||
5189 | /* | ||
5190 | * Initialize or reset the forechannel and backchannel tables | 5176 | * Initialize or reset the forechannel and backchannel tables |
5191 | */ | 5177 | */ |
5192 | static int nfs4_setup_session_slot_tables(struct nfs4_session *ses) | 5178 | static int nfs4_setup_session_slot_tables(struct nfs4_session *ses) |
@@ -5197,25 +5183,16 @@ static int nfs4_setup_session_slot_tables(struct nfs4_session *ses) | |||
5197 | dprintk("--> %s\n", __func__); | 5183 | dprintk("--> %s\n", __func__); |
5198 | /* Fore channel */ | 5184 | /* Fore channel */ |
5199 | tbl = &ses->fc_slot_table; | 5185 | tbl = &ses->fc_slot_table; |
5200 | if (tbl->slots == NULL) { | 5186 | status = nfs4_realloc_slot_table(tbl, ses->fc_attrs.max_reqs, 1); |
5201 | status = nfs4_init_slot_table(tbl, ses->fc_attrs.max_reqs, 1); | 5187 | if (status) /* -ENOMEM */ |
5202 | if (status) /* -ENOMEM */ | 5188 | return status; |
5203 | return status; | ||
5204 | } else { | ||
5205 | status = nfs4_reset_slot_table(tbl, ses->fc_attrs.max_reqs, 1); | ||
5206 | if (status) | ||
5207 | return status; | ||
5208 | } | ||
5209 | /* Back channel */ | 5189 | /* Back channel */ |
5210 | tbl = &ses->bc_slot_table; | 5190 | tbl = &ses->bc_slot_table; |
5211 | if (tbl->slots == NULL) { | 5191 | status = nfs4_realloc_slot_table(tbl, ses->bc_attrs.max_reqs, 0); |
5212 | status = nfs4_init_slot_table(tbl, ses->bc_attrs.max_reqs, 0); | 5192 | if (status && tbl->slots == NULL) |
5213 | if (status) | 5193 | /* Fore and back channel share a connection so get |
5214 | /* Fore and back channel share a connection so get | 5194 | * both slot tables or neither */ |
5215 | * both slot tables or neither */ | 5195 | nfs4_destroy_slot_tables(ses); |
5216 | nfs4_destroy_slot_tables(ses); | ||
5217 | } else | ||
5218 | status = nfs4_reset_slot_table(tbl, ses->bc_attrs.max_reqs, 0); | ||
5219 | return status; | 5196 | return status; |
5220 | } | 5197 | } |
5221 | 5198 | ||
diff --git a/fs/nfs/nfs4state.c b/fs/nfs/nfs4state.c index bae959e294cd..2f760604246f 100644 --- a/fs/nfs/nfs4state.c +++ b/fs/nfs/nfs4state.c | |||
@@ -1106,6 +1106,8 @@ void nfs4_schedule_stateid_recovery(const struct nfs_server *server, struct nfs4 | |||
1106 | { | 1106 | { |
1107 | struct nfs_client *clp = server->nfs_client; | 1107 | struct nfs_client *clp = server->nfs_client; |
1108 | 1108 | ||
1109 | if (test_and_clear_bit(NFS_DELEGATED_STATE, &state->flags)) | ||
1110 | nfs_async_inode_return_delegation(state->inode, &state->stateid); | ||
1109 | nfs4_state_mark_reclaim_nograce(clp, state); | 1111 | nfs4_state_mark_reclaim_nograce(clp, state); |
1110 | nfs4_schedule_state_manager(clp); | 1112 | nfs4_schedule_state_manager(clp); |
1111 | } | 1113 | } |
diff --git a/fs/nfs/nfs4xdr.c b/fs/nfs/nfs4xdr.c index 7d3ba1ff787c..bca8c77e5fe0 100644 --- a/fs/nfs/nfs4xdr.c +++ b/fs/nfs/nfs4xdr.c | |||
@@ -2563,7 +2563,6 @@ static void nfs4_xdr_enc_getacl(struct rpc_rqst *req, struct xdr_stream *xdr, | |||
2563 | 2563 | ||
2564 | xdr_inline_pages(&req->rq_rcv_buf, replen << 2, | 2564 | xdr_inline_pages(&req->rq_rcv_buf, replen << 2, |
2565 | args->acl_pages, args->acl_pgbase, args->acl_len); | 2565 | args->acl_pages, args->acl_pgbase, args->acl_len); |
2566 | xdr_set_scratch_buffer(xdr, page_address(args->acl_scratch), PAGE_SIZE); | ||
2567 | 2566 | ||
2568 | encode_nops(&hdr); | 2567 | encode_nops(&hdr); |
2569 | } | 2568 | } |
@@ -6132,6 +6131,10 @@ nfs4_xdr_dec_getacl(struct rpc_rqst *rqstp, struct xdr_stream *xdr, | |||
6132 | struct compound_hdr hdr; | 6131 | struct compound_hdr hdr; |
6133 | int status; | 6132 | int status; |
6134 | 6133 | ||
6134 | if (res->acl_scratch != NULL) { | ||
6135 | void *p = page_address(res->acl_scratch); | ||
6136 | xdr_set_scratch_buffer(xdr, p, PAGE_SIZE); | ||
6137 | } | ||
6135 | status = decode_compound_hdr(xdr, &hdr); | 6138 | status = decode_compound_hdr(xdr, &hdr); |
6136 | if (status) | 6139 | if (status) |
6137 | goto out; | 6140 | goto out; |
diff --git a/fs/proc/base.c b/fs/proc/base.c index 9cde9edf9c4d..d4548dd49b02 100644 --- a/fs/proc/base.c +++ b/fs/proc/base.c | |||
@@ -198,26 +198,6 @@ static int proc_root_link(struct dentry *dentry, struct path *path) | |||
198 | return result; | 198 | return result; |
199 | } | 199 | } |
200 | 200 | ||
201 | static struct mm_struct *mm_access(struct task_struct *task, unsigned int mode) | ||
202 | { | ||
203 | struct mm_struct *mm; | ||
204 | int err; | ||
205 | |||
206 | err = mutex_lock_killable(&task->signal->cred_guard_mutex); | ||
207 | if (err) | ||
208 | return ERR_PTR(err); | ||
209 | |||
210 | mm = get_task_mm(task); | ||
211 | if (mm && mm != current->mm && | ||
212 | !ptrace_may_access(task, mode)) { | ||
213 | mmput(mm); | ||
214 | mm = ERR_PTR(-EACCES); | ||
215 | } | ||
216 | mutex_unlock(&task->signal->cred_guard_mutex); | ||
217 | |||
218 | return mm; | ||
219 | } | ||
220 | |||
221 | struct mm_struct *mm_for_maps(struct task_struct *task) | 201 | struct mm_struct *mm_for_maps(struct task_struct *task) |
222 | { | 202 | { |
223 | return mm_access(task, PTRACE_MODE_READ); | 203 | return mm_access(task, PTRACE_MODE_READ); |
@@ -711,6 +691,13 @@ static int mem_open(struct inode* inode, struct file* file) | |||
711 | if (IS_ERR(mm)) | 691 | if (IS_ERR(mm)) |
712 | return PTR_ERR(mm); | 692 | return PTR_ERR(mm); |
713 | 693 | ||
694 | if (mm) { | ||
695 | /* ensure this mm_struct can't be freed */ | ||
696 | atomic_inc(&mm->mm_count); | ||
697 | /* but do not pin its memory */ | ||
698 | mmput(mm); | ||
699 | } | ||
700 | |||
714 | /* OK to pass negative loff_t, we can catch out-of-range */ | 701 | /* OK to pass negative loff_t, we can catch out-of-range */ |
715 | file->f_mode |= FMODE_UNSIGNED_OFFSET; | 702 | file->f_mode |= FMODE_UNSIGNED_OFFSET; |
716 | file->private_data = mm; | 703 | file->private_data = mm; |
@@ -718,57 +705,13 @@ static int mem_open(struct inode* inode, struct file* file) | |||
718 | return 0; | 705 | return 0; |
719 | } | 706 | } |
720 | 707 | ||
721 | static ssize_t mem_read(struct file * file, char __user * buf, | 708 | static ssize_t mem_rw(struct file *file, char __user *buf, |
722 | size_t count, loff_t *ppos) | 709 | size_t count, loff_t *ppos, int write) |
723 | { | 710 | { |
724 | int ret; | ||
725 | char *page; | ||
726 | unsigned long src = *ppos; | ||
727 | struct mm_struct *mm = file->private_data; | 711 | struct mm_struct *mm = file->private_data; |
728 | 712 | unsigned long addr = *ppos; | |
729 | if (!mm) | 713 | ssize_t copied; |
730 | return 0; | ||
731 | |||
732 | page = (char *)__get_free_page(GFP_TEMPORARY); | ||
733 | if (!page) | ||
734 | return -ENOMEM; | ||
735 | |||
736 | ret = 0; | ||
737 | |||
738 | while (count > 0) { | ||
739 | int this_len, retval; | ||
740 | |||
741 | this_len = (count > PAGE_SIZE) ? PAGE_SIZE : count; | ||
742 | retval = access_remote_vm(mm, src, page, this_len, 0); | ||
743 | if (!retval) { | ||
744 | if (!ret) | ||
745 | ret = -EIO; | ||
746 | break; | ||
747 | } | ||
748 | |||
749 | if (copy_to_user(buf, page, retval)) { | ||
750 | ret = -EFAULT; | ||
751 | break; | ||
752 | } | ||
753 | |||
754 | ret += retval; | ||
755 | src += retval; | ||
756 | buf += retval; | ||
757 | count -= retval; | ||
758 | } | ||
759 | *ppos = src; | ||
760 | |||
761 | free_page((unsigned long) page); | ||
762 | return ret; | ||
763 | } | ||
764 | |||
765 | static ssize_t mem_write(struct file * file, const char __user *buf, | ||
766 | size_t count, loff_t *ppos) | ||
767 | { | ||
768 | int copied; | ||
769 | char *page; | 714 | char *page; |
770 | unsigned long dst = *ppos; | ||
771 | struct mm_struct *mm = file->private_data; | ||
772 | 715 | ||
773 | if (!mm) | 716 | if (!mm) |
774 | return 0; | 717 | return 0; |
@@ -778,31 +721,54 @@ static ssize_t mem_write(struct file * file, const char __user *buf, | |||
778 | return -ENOMEM; | 721 | return -ENOMEM; |
779 | 722 | ||
780 | copied = 0; | 723 | copied = 0; |
724 | if (!atomic_inc_not_zero(&mm->mm_users)) | ||
725 | goto free; | ||
726 | |||
781 | while (count > 0) { | 727 | while (count > 0) { |
782 | int this_len, retval; | 728 | int this_len = min_t(int, count, PAGE_SIZE); |
783 | 729 | ||
784 | this_len = (count > PAGE_SIZE) ? PAGE_SIZE : count; | 730 | if (write && copy_from_user(page, buf, this_len)) { |
785 | if (copy_from_user(page, buf, this_len)) { | ||
786 | copied = -EFAULT; | 731 | copied = -EFAULT; |
787 | break; | 732 | break; |
788 | } | 733 | } |
789 | retval = access_remote_vm(mm, dst, page, this_len, 1); | 734 | |
790 | if (!retval) { | 735 | this_len = access_remote_vm(mm, addr, page, this_len, write); |
736 | if (!this_len) { | ||
791 | if (!copied) | 737 | if (!copied) |
792 | copied = -EIO; | 738 | copied = -EIO; |
793 | break; | 739 | break; |
794 | } | 740 | } |
795 | copied += retval; | 741 | |
796 | buf += retval; | 742 | if (!write && copy_to_user(buf, page, this_len)) { |
797 | dst += retval; | 743 | copied = -EFAULT; |
798 | count -= retval; | 744 | break; |
745 | } | ||
746 | |||
747 | buf += this_len; | ||
748 | addr += this_len; | ||
749 | copied += this_len; | ||
750 | count -= this_len; | ||
799 | } | 751 | } |
800 | *ppos = dst; | 752 | *ppos = addr; |
801 | 753 | ||
754 | mmput(mm); | ||
755 | free: | ||
802 | free_page((unsigned long) page); | 756 | free_page((unsigned long) page); |
803 | return copied; | 757 | return copied; |
804 | } | 758 | } |
805 | 759 | ||
760 | static ssize_t mem_read(struct file *file, char __user *buf, | ||
761 | size_t count, loff_t *ppos) | ||
762 | { | ||
763 | return mem_rw(file, buf, count, ppos, 0); | ||
764 | } | ||
765 | |||
766 | static ssize_t mem_write(struct file *file, const char __user *buf, | ||
767 | size_t count, loff_t *ppos) | ||
768 | { | ||
769 | return mem_rw(file, (char __user*)buf, count, ppos, 1); | ||
770 | } | ||
771 | |||
806 | loff_t mem_lseek(struct file *file, loff_t offset, int orig) | 772 | loff_t mem_lseek(struct file *file, loff_t offset, int orig) |
807 | { | 773 | { |
808 | switch (orig) { | 774 | switch (orig) { |
@@ -822,8 +788,8 @@ loff_t mem_lseek(struct file *file, loff_t offset, int orig) | |||
822 | static int mem_release(struct inode *inode, struct file *file) | 788 | static int mem_release(struct inode *inode, struct file *file) |
823 | { | 789 | { |
824 | struct mm_struct *mm = file->private_data; | 790 | struct mm_struct *mm = file->private_data; |
825 | 791 | if (mm) | |
826 | mmput(mm); | 792 | mmdrop(mm); |
827 | return 0; | 793 | return 0; |
828 | } | 794 | } |
829 | 795 | ||