0001
0002
0003
0004
0005
0006
0007
0008
0009
0010 #define KMSG_COMPONENT "hmcdrv"
0011 #define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
0012
0013 #include <linux/kernel.h>
0014 #include <linux/mm.h>
0015 #include <linux/jiffies.h>
0016
0017 #include "hmcdrv_ftp.h"
0018 #include "hmcdrv_cache.h"
0019
0020 #define HMCDRV_CACHE_TIMEOUT 30
0021
0022
0023
0024
0025
0026
0027
0028
0029
0030
0031
0032
0033
0034
0035
0036 struct hmcdrv_cache_entry {
0037 enum hmcdrv_ftp_cmdid id;
0038 char fname[HMCDRV_FTP_FIDENT_MAX];
0039 size_t fsize;
0040 loff_t ofs;
0041 unsigned long timeout;
0042 void *content;
0043 size_t len;
0044 };
0045
0046 static int hmcdrv_cache_order;
0047
0048 static struct hmcdrv_cache_entry hmcdrv_cache_file = {
0049 .fsize = SIZE_MAX,
0050 .ofs = -1,
0051 .len = 0,
0052 .fname = {'\0'}
0053 };
0054
0055
0056
0057
0058
0059
0060
0061
0062 static ssize_t hmcdrv_cache_get(const struct hmcdrv_ftp_cmdspec *ftp)
0063 {
0064 loff_t pos;
0065 ssize_t len;
0066
0067 if ((ftp->id != hmcdrv_cache_file.id) ||
0068 strcmp(hmcdrv_cache_file.fname, ftp->fname))
0069 return -1;
0070
0071 if (ftp->ofs >= hmcdrv_cache_file.fsize)
0072 return 0;
0073
0074 if ((hmcdrv_cache_file.ofs < 0) ||
0075 time_after(jiffies, hmcdrv_cache_file.timeout))
0076 return -1;
0077
0078
0079
0080
0081 len = hmcdrv_cache_file.fsize - ftp->ofs;
0082
0083 if (len > ftp->len)
0084 len = ftp->len;
0085
0086
0087
0088
0089 pos = ftp->ofs - hmcdrv_cache_file.ofs;
0090
0091 if ((pos >= 0) &&
0092 ((pos + len) <= hmcdrv_cache_file.len)) {
0093
0094 memcpy(ftp->buf,
0095 hmcdrv_cache_file.content + pos,
0096 len);
0097 pr_debug("using cached content of '%s', returning %zd/%zd bytes\n",
0098 hmcdrv_cache_file.fname, len,
0099 hmcdrv_cache_file.fsize);
0100
0101 return len;
0102 }
0103
0104 return -1;
0105 }
0106
0107
0108
0109
0110
0111
0112
0113
0114 static ssize_t hmcdrv_cache_do(const struct hmcdrv_ftp_cmdspec *ftp,
0115 hmcdrv_cache_ftpfunc func)
0116 {
0117 ssize_t len;
0118
0119
0120
0121
0122
0123
0124 if ((ftp->len > 0) && (hmcdrv_cache_file.len >= ftp->len)) {
0125
0126
0127
0128
0129
0130 struct hmcdrv_ftp_cmdspec cftp = *ftp;
0131 cftp.buf = hmcdrv_cache_file.content;
0132 cftp.len = hmcdrv_cache_file.len;
0133
0134 len = func(&cftp, &hmcdrv_cache_file.fsize);
0135
0136 if (len > 0) {
0137 pr_debug("caching %zd bytes content for '%s'\n",
0138 len, ftp->fname);
0139
0140 if (len > ftp->len)
0141 len = ftp->len;
0142
0143 hmcdrv_cache_file.ofs = ftp->ofs;
0144 hmcdrv_cache_file.timeout = jiffies +
0145 HMCDRV_CACHE_TIMEOUT * HZ;
0146 memcpy(ftp->buf, hmcdrv_cache_file.content, len);
0147 }
0148 } else {
0149 len = func(ftp, &hmcdrv_cache_file.fsize);
0150 hmcdrv_cache_file.ofs = -1;
0151 }
0152
0153 if (len > 0) {
0154
0155
0156
0157 strlcpy(hmcdrv_cache_file.fname, ftp->fname,
0158 HMCDRV_FTP_FIDENT_MAX);
0159 hmcdrv_cache_file.id = ftp->id;
0160 pr_debug("caching cmd %d, file size %zu for '%s'\n",
0161 ftp->id, hmcdrv_cache_file.fsize, ftp->fname);
0162 }
0163
0164 return len;
0165 }
0166
0167
0168
0169
0170
0171
0172
0173
0174
0175
0176
0177 ssize_t hmcdrv_cache_cmd(const struct hmcdrv_ftp_cmdspec *ftp,
0178 hmcdrv_cache_ftpfunc func)
0179 {
0180 ssize_t len;
0181
0182 if ((ftp->id == HMCDRV_FTP_DIR) ||
0183 (ftp->id == HMCDRV_FTP_NLIST) ||
0184 (ftp->id == HMCDRV_FTP_GET)) {
0185
0186 len = hmcdrv_cache_get(ftp);
0187
0188 if (len >= 0)
0189 return len;
0190
0191 len = hmcdrv_cache_do(ftp, func);
0192
0193 if (len >= 0)
0194 return len;
0195
0196 } else {
0197 len = func(ftp, NULL);
0198 }
0199
0200
0201
0202
0203 hmcdrv_cache_file.id = HMCDRV_FTP_NOOP;
0204 hmcdrv_cache_file.fsize = LLONG_MAX;
0205 hmcdrv_cache_file.ofs = -1;
0206
0207 return len;
0208 }
0209
0210
0211
0212
0213
0214
0215
0216 int hmcdrv_cache_startup(size_t cachesize)
0217 {
0218 if (cachesize > 0) {
0219 hmcdrv_cache_order = get_order(cachesize);
0220 hmcdrv_cache_file.content =
0221 (void *) __get_free_pages(GFP_KERNEL | GFP_DMA,
0222 hmcdrv_cache_order);
0223
0224 if (!hmcdrv_cache_file.content) {
0225 pr_err("Allocating the requested cache size of %zu bytes failed\n",
0226 cachesize);
0227 return -ENOMEM;
0228 }
0229
0230 pr_debug("content cache enabled, size is %zu bytes\n",
0231 cachesize);
0232 }
0233
0234 hmcdrv_cache_file.len = cachesize;
0235 return 0;
0236 }
0237
0238
0239
0240
0241 void hmcdrv_cache_shutdown(void)
0242 {
0243 if (hmcdrv_cache_file.content) {
0244 free_pages((unsigned long) hmcdrv_cache_file.content,
0245 hmcdrv_cache_order);
0246 hmcdrv_cache_file.content = NULL;
0247 }
0248
0249 hmcdrv_cache_file.id = HMCDRV_FTP_NOOP;
0250 hmcdrv_cache_file.fsize = LLONG_MAX;
0251 hmcdrv_cache_file.ofs = -1;
0252 hmcdrv_cache_file.len = 0;
0253 }