aboutsummaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
Diffstat (limited to 'fs')
-rw-r--r--fs/ceph/caps.c4
-rw-r--r--fs/ceph/dir.c4
-rw-r--r--fs/ceph/mds_client.c10
-rw-r--r--fs/ceph/mds_client.h7
-rw-r--r--fs/ceph/xattr.c4
-rw-r--r--fs/logfs/dev_mtd.c6
-rw-r--r--fs/nfs/nfs4proc.c115
-rw-r--r--fs/nfs/nfs4state.c2
-rw-r--r--fs/nfs/nfs4xdr.c5
-rw-r--r--fs/proc/base.c126
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
113static struct ceph_vxattr_cb ceph_file_vxattrs[] = { 113static 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
118static struct ceph_vxattr_cb *ceph_inode_vxattrs(struct inode *inode) 120static 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
5107static 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
5112static 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 */
5110static int nfs4_reset_slot_table(struct nfs4_slot_table *tbl, u32 max_reqs, 5136static 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);
5140out: 5156out:
@@ -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 */
5162static 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);
5184out:
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 */
5192static int nfs4_setup_session_slot_tables(struct nfs4_session *ses) 5178static 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
201static 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
221struct mm_struct *mm_for_maps(struct task_struct *task) 201struct 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
721static ssize_t mem_read(struct file * file, char __user * buf, 708static 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
765static 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);
755free:
802 free_page((unsigned long) page); 756 free_page((unsigned long) page);
803 return copied; 757 return copied;
804} 758}
805 759
760static 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
766static 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
806loff_t mem_lseek(struct file *file, loff_t offset, int orig) 772loff_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)
822static int mem_release(struct inode *inode, struct file *file) 788static 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