0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023
0024
0025
0026
0027
0028
0029
0030
0031
0032
0033 #include <linux/percpu.h>
0034 #include <linux/seq_file.h>
0035 #include <linux/slab.h>
0036 #include <linux/proc_fs.h>
0037 #include <linux/export.h>
0038
0039 #include "rds.h"
0040
0041
0042
0043
0044
0045
0046
0047
0048
0049
0050
0051
0052
0053
0054
0055
0056
0057
0058
0059
0060
0061
0062
0063
0064 struct rds_info_iterator {
0065 struct page **pages;
0066 void *addr;
0067 unsigned long offset;
0068 };
0069
0070 static DEFINE_SPINLOCK(rds_info_lock);
0071 static rds_info_func rds_info_funcs[RDS_INFO_LAST - RDS_INFO_FIRST + 1];
0072
0073 void rds_info_register_func(int optname, rds_info_func func)
0074 {
0075 int offset = optname - RDS_INFO_FIRST;
0076
0077 BUG_ON(optname < RDS_INFO_FIRST || optname > RDS_INFO_LAST);
0078
0079 spin_lock(&rds_info_lock);
0080 BUG_ON(rds_info_funcs[offset]);
0081 rds_info_funcs[offset] = func;
0082 spin_unlock(&rds_info_lock);
0083 }
0084 EXPORT_SYMBOL_GPL(rds_info_register_func);
0085
0086 void rds_info_deregister_func(int optname, rds_info_func func)
0087 {
0088 int offset = optname - RDS_INFO_FIRST;
0089
0090 BUG_ON(optname < RDS_INFO_FIRST || optname > RDS_INFO_LAST);
0091
0092 spin_lock(&rds_info_lock);
0093 BUG_ON(rds_info_funcs[offset] != func);
0094 rds_info_funcs[offset] = NULL;
0095 spin_unlock(&rds_info_lock);
0096 }
0097 EXPORT_SYMBOL_GPL(rds_info_deregister_func);
0098
0099
0100
0101
0102
0103
0104 void rds_info_iter_unmap(struct rds_info_iterator *iter)
0105 {
0106 if (iter->addr) {
0107 kunmap_atomic(iter->addr);
0108 iter->addr = NULL;
0109 }
0110 }
0111
0112
0113
0114
0115 void rds_info_copy(struct rds_info_iterator *iter, void *data,
0116 unsigned long bytes)
0117 {
0118 unsigned long this;
0119
0120 while (bytes) {
0121 if (!iter->addr)
0122 iter->addr = kmap_atomic(*iter->pages);
0123
0124 this = min(bytes, PAGE_SIZE - iter->offset);
0125
0126 rdsdebug("page %p addr %p offset %lu this %lu data %p "
0127 "bytes %lu\n", *iter->pages, iter->addr,
0128 iter->offset, this, data, bytes);
0129
0130 memcpy(iter->addr + iter->offset, data, this);
0131
0132 data += this;
0133 bytes -= this;
0134 iter->offset += this;
0135
0136 if (iter->offset == PAGE_SIZE) {
0137 kunmap_atomic(iter->addr);
0138 iter->addr = NULL;
0139 iter->offset = 0;
0140 iter->pages++;
0141 }
0142 }
0143 }
0144 EXPORT_SYMBOL_GPL(rds_info_copy);
0145
0146
0147
0148
0149
0150
0151
0152
0153
0154
0155
0156
0157
0158 int rds_info_getsockopt(struct socket *sock, int optname, char __user *optval,
0159 int __user *optlen)
0160 {
0161 struct rds_info_iterator iter;
0162 struct rds_info_lengths lens;
0163 unsigned long nr_pages = 0;
0164 unsigned long start;
0165 rds_info_func func;
0166 struct page **pages = NULL;
0167 int ret;
0168 int len;
0169 int total;
0170
0171 if (get_user(len, optlen)) {
0172 ret = -EFAULT;
0173 goto out;
0174 }
0175
0176
0177 start = (unsigned long)optval;
0178 if (len < 0 || len > INT_MAX - PAGE_SIZE + 1 || start + len < start) {
0179 ret = -EINVAL;
0180 goto out;
0181 }
0182
0183
0184 if (len == 0)
0185 goto call_func;
0186
0187 nr_pages = (PAGE_ALIGN(start + len) - (start & PAGE_MASK))
0188 >> PAGE_SHIFT;
0189
0190 pages = kmalloc_array(nr_pages, sizeof(struct page *), GFP_KERNEL);
0191 if (!pages) {
0192 ret = -ENOMEM;
0193 goto out;
0194 }
0195 ret = pin_user_pages_fast(start, nr_pages, FOLL_WRITE, pages);
0196 if (ret != nr_pages) {
0197 if (ret > 0)
0198 nr_pages = ret;
0199 else
0200 nr_pages = 0;
0201 ret = -EAGAIN;
0202 goto out;
0203 }
0204
0205 rdsdebug("len %d nr_pages %lu\n", len, nr_pages);
0206
0207 call_func:
0208 func = rds_info_funcs[optname - RDS_INFO_FIRST];
0209 if (!func) {
0210 ret = -ENOPROTOOPT;
0211 goto out;
0212 }
0213
0214 iter.pages = pages;
0215 iter.addr = NULL;
0216 iter.offset = start & (PAGE_SIZE - 1);
0217
0218 func(sock, len, &iter, &lens);
0219 BUG_ON(lens.each == 0);
0220
0221 total = lens.nr * lens.each;
0222
0223 rds_info_iter_unmap(&iter);
0224
0225 if (total > len) {
0226 len = total;
0227 ret = -ENOSPC;
0228 } else {
0229 len = total;
0230 ret = lens.each;
0231 }
0232
0233 if (put_user(len, optlen))
0234 ret = -EFAULT;
0235
0236 out:
0237 if (pages)
0238 unpin_user_pages(pages, nr_pages);
0239 kfree(pages);
0240
0241 return ret;
0242 }