diff options
| -rw-r--r-- | ipc/shm.c | 240 |
1 files changed, 155 insertions, 85 deletions
| @@ -37,11 +37,21 @@ | |||
| 37 | #include <linux/seq_file.h> | 37 | #include <linux/seq_file.h> |
| 38 | #include <linux/mutex.h> | 38 | #include <linux/mutex.h> |
| 39 | #include <linux/nsproxy.h> | 39 | #include <linux/nsproxy.h> |
| 40 | #include <linux/mount.h> | ||
| 40 | 41 | ||
| 41 | #include <asm/uaccess.h> | 42 | #include <asm/uaccess.h> |
| 42 | 43 | ||
| 43 | #include "util.h" | 44 | #include "util.h" |
| 44 | 45 | ||
| 46 | struct shm_file_data { | ||
| 47 | int id; | ||
| 48 | struct ipc_namespace *ns; | ||
| 49 | struct file *file; | ||
| 50 | const struct vm_operations_struct *vm_ops; | ||
| 51 | }; | ||
| 52 | |||
| 53 | #define shm_file_data(file) (*((struct shm_file_data **)&(file)->private_data)) | ||
| 54 | |||
| 45 | static const struct file_operations shm_file_operations; | 55 | static const struct file_operations shm_file_operations; |
| 46 | static struct vm_operations_struct shm_vm_ops; | 56 | static struct vm_operations_struct shm_vm_ops; |
| 47 | 57 | ||
| @@ -60,8 +70,8 @@ static struct ipc_ids init_shm_ids; | |||
| 60 | 70 | ||
| 61 | static int newseg (struct ipc_namespace *ns, key_t key, | 71 | static int newseg (struct ipc_namespace *ns, key_t key, |
| 62 | int shmflg, size_t size); | 72 | int shmflg, size_t size); |
| 63 | static void shm_open (struct vm_area_struct *shmd); | 73 | static void shm_open(struct vm_area_struct *vma); |
| 64 | static void shm_close (struct vm_area_struct *shmd); | 74 | static void shm_close(struct vm_area_struct *vma); |
| 65 | static void shm_destroy (struct ipc_namespace *ns, struct shmid_kernel *shp); | 75 | static void shm_destroy (struct ipc_namespace *ns, struct shmid_kernel *shp); |
| 66 | #ifdef CONFIG_PROC_FS | 76 | #ifdef CONFIG_PROC_FS |
| 67 | static int sysvipc_shm_proc_show(struct seq_file *s, void *it); | 77 | static int sysvipc_shm_proc_show(struct seq_file *s, void *it); |
| @@ -150,11 +160,14 @@ static inline int shm_addid(struct ipc_namespace *ns, struct shmid_kernel *shp) | |||
| 150 | 160 | ||
| 151 | 161 | ||
| 152 | 162 | ||
| 153 | static inline void shm_inc(struct ipc_namespace *ns, int id) | 163 | /* This is called by fork, once for every shm attach. */ |
| 164 | static void shm_open(struct vm_area_struct *vma) | ||
| 154 | { | 165 | { |
| 166 | struct file *file = vma->vm_file; | ||
| 167 | struct shm_file_data *sfd = shm_file_data(file); | ||
| 155 | struct shmid_kernel *shp; | 168 | struct shmid_kernel *shp; |
| 156 | 169 | ||
| 157 | shp = shm_lock(ns, id); | 170 | shp = shm_lock(sfd->ns, sfd->id); |
| 158 | BUG_ON(!shp); | 171 | BUG_ON(!shp); |
| 159 | shp->shm_atim = get_seconds(); | 172 | shp->shm_atim = get_seconds(); |
| 160 | shp->shm_lprid = current->tgid; | 173 | shp->shm_lprid = current->tgid; |
| @@ -162,15 +175,6 @@ static inline void shm_inc(struct ipc_namespace *ns, int id) | |||
| 162 | shm_unlock(shp); | 175 | shm_unlock(shp); |
| 163 | } | 176 | } |
| 164 | 177 | ||
| 165 | #define shm_file_ns(file) (*((struct ipc_namespace **)&(file)->private_data)) | ||
| 166 | |||
| 167 | /* This is called by fork, once for every shm attach. */ | ||
| 168 | static void shm_open(struct vm_area_struct *shmd) | ||
| 169 | { | ||
| 170 | shm_inc(shm_file_ns(shmd->vm_file), | ||
| 171 | shmd->vm_file->f_path.dentry->d_inode->i_ino); | ||
| 172 | } | ||
| 173 | |||
| 174 | /* | 178 | /* |
| 175 | * shm_destroy - free the struct shmid_kernel | 179 | * shm_destroy - free the struct shmid_kernel |
| 176 | * | 180 | * |
| @@ -195,23 +199,21 @@ static void shm_destroy(struct ipc_namespace *ns, struct shmid_kernel *shp) | |||
| 195 | } | 199 | } |
| 196 | 200 | ||
| 197 | /* | 201 | /* |
| 198 | * remove the attach descriptor shmd. | 202 | * remove the attach descriptor vma. |
| 199 | * free memory for segment if it is marked destroyed. | 203 | * free memory for segment if it is marked destroyed. |
| 200 | * The descriptor has already been removed from the current->mm->mmap list | 204 | * The descriptor has already been removed from the current->mm->mmap list |
| 201 | * and will later be kfree()d. | 205 | * and will later be kfree()d. |
| 202 | */ | 206 | */ |
| 203 | static void shm_close (struct vm_area_struct *shmd) | 207 | static void shm_close(struct vm_area_struct *vma) |
| 204 | { | 208 | { |
| 205 | struct file * file = shmd->vm_file; | 209 | struct file * file = vma->vm_file; |
| 206 | int id = file->f_path.dentry->d_inode->i_ino; | 210 | struct shm_file_data *sfd = shm_file_data(file); |
| 207 | struct shmid_kernel *shp; | 211 | struct shmid_kernel *shp; |
| 208 | struct ipc_namespace *ns; | 212 | struct ipc_namespace *ns = sfd->ns; |
| 209 | |||
| 210 | ns = shm_file_ns(file); | ||
| 211 | 213 | ||
| 212 | mutex_lock(&shm_ids(ns).mutex); | 214 | mutex_lock(&shm_ids(ns).mutex); |
| 213 | /* remove from the list of attaches of the shm segment */ | 215 | /* remove from the list of attaches of the shm segment */ |
| 214 | shp = shm_lock(ns, id); | 216 | shp = shm_lock(ns, sfd->id); |
| 215 | BUG_ON(!shp); | 217 | BUG_ON(!shp); |
| 216 | shp->shm_lprid = current->tgid; | 218 | shp->shm_lprid = current->tgid; |
| 217 | shp->shm_dtim = get_seconds(); | 219 | shp->shm_dtim = get_seconds(); |
| @@ -224,46 +226,91 @@ static void shm_close (struct vm_area_struct *shmd) | |||
| 224 | mutex_unlock(&shm_ids(ns).mutex); | 226 | mutex_unlock(&shm_ids(ns).mutex); |
| 225 | } | 227 | } |
| 226 | 228 | ||
| 229 | struct page *shm_nopage(struct vm_area_struct *vma, unsigned long address, | ||
| 230 | int *type) | ||
| 231 | { | ||
| 232 | struct file *file = vma->vm_file; | ||
| 233 | struct shm_file_data *sfd = shm_file_data(file); | ||
| 234 | |||
| 235 | return sfd->vm_ops->nopage(vma, address, type); | ||
| 236 | } | ||
| 237 | |||
| 238 | #ifdef CONFIG_NUMA | ||
| 239 | int shm_set_policy(struct vm_area_struct *vma, struct mempolicy *new) | ||
| 240 | { | ||
| 241 | struct file *file = vma->vm_file; | ||
| 242 | struct shm_file_data *sfd = shm_file_data(file); | ||
| 243 | int err = 0; | ||
| 244 | if (sfd->vm_ops->set_policy) | ||
| 245 | err = sfd->vm_ops->set_policy(vma, new); | ||
| 246 | return err; | ||
| 247 | } | ||
| 248 | |||
| 249 | struct mempolicy *shm_get_policy(struct vm_area_struct *vma, unsigned long addr) | ||
| 250 | { | ||
| 251 | struct file *file = vma->vm_file; | ||
| 252 | struct shm_file_data *sfd = shm_file_data(file); | ||
| 253 | struct mempolicy *pol = NULL; | ||
| 254 | |||
| 255 | if (sfd->vm_ops->get_policy) | ||
| 256 | pol = sfd->vm_ops->get_policy(vma, addr); | ||
| 257 | else | ||
| 258 | pol = vma->vm_policy; | ||
| 259 | return pol; | ||
| 260 | } | ||
| 261 | #endif | ||
| 262 | |||
| 227 | static int shm_mmap(struct file * file, struct vm_area_struct * vma) | 263 | static int shm_mmap(struct file * file, struct vm_area_struct * vma) |
| 228 | { | 264 | { |
| 265 | struct shm_file_data *sfd = shm_file_data(file); | ||
| 229 | int ret; | 266 | int ret; |
| 230 | 267 | ||
| 231 | ret = shmem_mmap(file, vma); | 268 | ret = sfd->file->f_op->mmap(sfd->file, vma); |
| 232 | if (ret == 0) { | 269 | if (ret != 0) |
| 233 | vma->vm_ops = &shm_vm_ops; | 270 | return ret; |
| 234 | if (!(vma->vm_flags & VM_WRITE)) | 271 | sfd->vm_ops = vma->vm_ops; |
| 235 | vma->vm_flags &= ~VM_MAYWRITE; | 272 | vma->vm_ops = &shm_vm_ops; |
| 236 | shm_inc(shm_file_ns(file), file->f_path.dentry->d_inode->i_ino); | 273 | shm_open(vma); |
| 237 | } | ||
| 238 | 274 | ||
| 239 | return ret; | 275 | return ret; |
| 240 | } | 276 | } |
| 241 | 277 | ||
| 242 | static int shm_release(struct inode *ino, struct file *file) | 278 | static int shm_release(struct inode *ino, struct file *file) |
| 243 | { | 279 | { |
| 244 | struct ipc_namespace *ns; | 280 | struct shm_file_data *sfd = shm_file_data(file); |
| 245 | 281 | ||
| 246 | ns = shm_file_ns(file); | 282 | put_ipc_ns(sfd->ns); |
| 247 | put_ipc_ns(ns); | 283 | shm_file_data(file) = NULL; |
| 248 | shm_file_ns(file) = NULL; | 284 | kfree(sfd); |
| 249 | return 0; | 285 | return 0; |
| 250 | } | 286 | } |
| 251 | 287 | ||
| 288 | #ifndef CONFIG_MMU | ||
| 289 | static unsigned long shm_get_unmapped_area(struct file *file, | ||
| 290 | unsigned long addr, unsigned long len, unsigned long pgoff, | ||
| 291 | unsigned long flags) | ||
| 292 | { | ||
| 293 | struct shm_file_data *sfd = shm_file_data(file); | ||
| 294 | return sfd->file->f_op->get_unmapped_area(sfd->file, addr, len, pgoff, | ||
| 295 | flags); | ||
| 296 | } | ||
| 297 | #else | ||
| 298 | #define shm_get_unmapped_area NULL | ||
| 299 | #endif | ||
| 300 | |||
| 252 | static const struct file_operations shm_file_operations = { | 301 | static const struct file_operations shm_file_operations = { |
| 253 | .mmap = shm_mmap, | 302 | .mmap = shm_mmap, |
| 254 | .release = shm_release, | 303 | .release = shm_release, |
| 255 | #ifndef CONFIG_MMU | 304 | .get_unmapped_area = shm_get_unmapped_area, |
| 256 | .get_unmapped_area = shmem_get_unmapped_area, | ||
