1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18#include <linux/config.h>
19#include <linux/slab.h>
20#include <linux/mm.h>
21#include <linux/hugetlb.h>
22#include <linux/shm.h>
23#include <linux/init.h>
24#include <linux/file.h>
25#include <linux/mman.h>
26#include <linux/proc_fs.h>
27#include <linux/shmem_fs.h>
28#include <linux/security.h>
29#include <asm/uaccess.h>
30
31#include "util.h"
32
33#define shm_flags shm_perm.mode
34
35static struct file_operations shm_file_operations;
36static struct vm_operations_struct shm_vm_ops;
37
38static struct ipc_ids shm_ids;
39
40#define shm_lock(id) ((struct shmid_kernel*)ipc_lock(&shm_ids,id))
41#define shm_unlock(shp) ipc_unlock(&(shp)->shm_perm)
42#define shm_get(id) ((struct shmid_kernel*)ipc_get(&shm_ids,id))
43#define shm_buildid(id, seq) \
44 ipc_buildid(&shm_ids, id, seq)
45
46static int newseg (key_t key, int shmflg, size_t size);
47static void shm_open (struct vm_area_struct *shmd);
48static void shm_close (struct vm_area_struct *shmd);
49#ifdef CONFIG_PROC_FS
50static int sysvipc_shm_read_proc(char *buffer, char **start, off_t offset, int length, int *eof, void *data);
51#endif
52
53size_t shm_ctlmax = SHMMAX;
54size_t shm_ctlall = SHMALL;
55int shm_ctlmni = SHMMNI;
56
57static int shm_tot;
58
59void __init shm_init (void)
60{
61 ipc_init_ids(&shm_ids, 1);
62#ifdef CONFIG_PROC_FS
63 create_proc_read_entry("sysvipc/shm", 0, NULL, sysvipc_shm_read_proc, NULL);
64#endif
65}
66
67static inline int shm_checkid(struct shmid_kernel *s, int id)
68{
69 if (ipc_checkid(&shm_ids,&s->shm_perm,id))
70 return -EIDRM;
71 return 0;
72}
73
74static inline struct shmid_kernel *shm_rmid(int id)
75{
76 return (struct shmid_kernel *)ipc_rmid(&shm_ids,id);
77}
78
79static inline int shm_addid(struct shmid_kernel *shp)
80{
81 return ipc_addid(&shm_ids, &shp->shm_perm, shm_ctlmni+1);
82}
83
84
85
86static inline void shm_inc (int id) {
87 struct shmid_kernel *shp;
88
89 if(!(shp = shm_lock(id)))
90 BUG();
91 shp->shm_atim = get_seconds();
92 shp->shm_lprid = current->tgid;
93 shp->shm_nattch++;
94 shm_unlock(shp);
95}
96
97
98static void shm_open (struct vm_area_struct *shmd)
99{
100 shm_inc (shmd->vm_file->f_dentry->d_inode->i_ino);
101}
102
103
104
105
106
107
108
109
110
111static void shm_destroy (struct shmid_kernel *shp)
112{
113 shm_tot -= (shp->shm_segsz + PAGE_SIZE - 1) >> PAGE_SHIFT;
114 shm_rmid (shp->id);
115 shm_unlock(shp);
116 if (!is_file_hugepages(shp->shm_file))
117 shmem_lock(shp->shm_file, 0);
118 fput (shp->shm_file);
119 security_shm_free(shp);
120 ipc_rcu_free(shp, sizeof(struct shmid_kernel));
121}
122
123
124
125
126
127
128
129static void shm_close (struct vm_area_struct *shmd)
130{
131 struct file * file = shmd->vm_file;
132 int id = file->f_dentry->d_inode->i_ino;
133 struct shmid_kernel *shp;
134
135 down (&shm_ids.sem);
136
137 if(!(shp = shm_lock(id)))
138 BUG();
139 shp->shm_lprid = current->tgid;
140 shp->shm_dtim = get_seconds();
141 shp->shm_nattch--;
142 if(shp->shm_nattch == 0 &&
143 shp->shm_flags & SHM_DEST)
144 shm_destroy (shp);
145 else
146 shm_unlock(shp);
147 up (&shm_ids.sem);
148}
149
150static int shm_mmap(struct file * file, struct vm_area_struct * vma)
151{
152 file_accessed(file);
153 vma->vm_ops = &shm_vm_ops;
154 shm_inc(file->f_dentry->d_inode->i_ino);
155 return 0;
156}
157
158static struct file_operations shm_file_operations = {
159 .mmap = shm_mmap
160};
161
162static struct vm_operations_struct shm_vm_ops = {
163 .open = shm_open,
164 .close = shm_close,
165 .nopage = shmem_nopage,
166#ifdef CONFIG_NUMA
167 .set_policy = shmem_set_policy,
168 .get_policy = shmem_get_policy,
169#endif
170};
171
172static int newseg (key_t key, int shmflg, size_t size)
173{
174 int error;
175 struct shmid_kernel *shp;
176 int numpages = (size + PAGE_SIZE -1) >> PAGE_SHIFT;
177 struct file * file;
178 char name[13];
179 int id;
180
181 if (size < SHMMIN || size > shm_ctlmax)
182 return -EINVAL;
183
184 if (shm_tot + numpages >= shm_ctlall)
185 return -ENOSPC;
186
187 shp = ipc_rcu_alloc(sizeof(*shp));
188 if (!shp)
189 return -ENOMEM;
190
191 shp->shm_perm.key = key;
192 shp->shm_flags = (shmflg & S_IRWXUGO);
193
194 shp->shm_perm.security = NULL;
195 error = security_shm_alloc(shp);
196 if (error) {
197 ipc_rcu_free(shp, sizeof(*shp));
198 return error;
199 }
200
201 if (shmflg & SHM_HUGETLB)
202 file = hugetlb_zero_setup(size);
203 else {
204 sprintf (name, "SYSV%08x", key);
205 file = shmem_file_setup(name, size, VM_ACCOUNT);
206 }
207 error = PTR_ERR(file);
208 if (IS_ERR(file))
209 goto no_file;
210
211 error = -ENOSPC;
212 id = shm_addid(shp);
213 if(id == -1)
214 goto no_id;
215
216 shp->shm_cprid = current->tgid;
217 shp->shm_lprid = 0;
218 shp->shm_atim = shp->shm_dtim = 0;
219 shp->shm_ctim = get_seconds();
220 shp->shm_segsz = size;
221 shp->shm_nattch = 0;
222 shp->id = shm_buildid(id,shp->shm_perm.seq);
223 shp->shm_file = file;
224 file->f_dentry->d_inode->i_ino = shp->id;
225 if (shmflg & SHM_HUGETLB)
226 set_file_hugepages(file);
227 else
228 file->f_op = &shm_file_operations;
229 shm_tot += numpages;
230 shm_unlock(shp);
231 return shp->id;
232
233no_id:
234 fput(file);
235no_file:
236 security_shm_free(shp);
237 ipc_rcu_free(shp, sizeof(*shp));
238 return error;
239}
240
241asmlinkage long sys_shmget (key_t key, size_t size, int shmflg)
242{
243 struct shmid_kernel *shp;
244 int err, id = 0;
245
246 down(&shm_ids.sem);
247 if (key == IPC_PRIVATE) {
248 err = newseg(key, shmflg, size);
249 } else if ((id = ipc_findkey(&shm_ids, key)) == -1) {
250 if (!(shmflg & IPC_CREAT))
251 err = -ENOENT;
252 else
253 err = newseg(key, shmflg, size);
254 } else if ((shmflg & IPC_CREAT) && (shmflg & IPC_EXCL)) {
255 err = -EEXIST;
256 } else {
257 shp = shm_lock(id);
258 if(shp==NULL)
259 BUG();
260 if (shp->shm_segsz < size)
261 err = -EINVAL;
262 else if (ipcperms(&shp->shm_perm, shmflg))
263 err = -EACCES;
264 else {
265 int shmid = shm_buildid(id, shp->shm_perm.seq);
266 err = security_shm_associate(shp, shmflg);
267 if (!err)
268 err = shmid;
269 }
270 shm_unlock(shp);
271 }
272 up(&shm_ids.sem);
273
274 return err;
275}
276
277static inline unsigned long copy_shmid_to_user(void __user *buf, struct shmid64_ds *in, int version)
278{
279 switch(version) {
280 case IPC_64:
281 return copy_to_user(buf, in, sizeof(*in));
282 case IPC_OLD:
283 {
284 struct shmid_ds out;
285
286 ipc64_perm_to_ipc_perm(&in->shm_perm, &out.shm_perm);
287 out.shm_segsz = in->shm_segsz;
288 out.shm_atime = in->shm_atime;
289 out.shm_dtime = in->shm_dtime;
290 out.shm_ctime = in->shm_ctime;
291 out.shm_cpid = in->shm_cpid;
292 out.shm_lpid = in->shm_lpid;
293 out.shm_nattch = in->shm_nattch;
294
295 return copy_to_user(buf, &out, sizeof(out));
296 }
297 default:
298 return -EINVAL;
299 }
300}
301
302struct shm_setbuf {
303 uid_t uid;
304 gid_t gid;
305 mode_t mode;
306};
307
308static inline unsigned long copy_shmid_from_user(struct shm_setbuf *out, void __user *buf, int version)
309{
310 switch(version) {
311 case IPC_64:
312 {
313 struct shmid64_ds tbuf;
314
315 if (copy_from_user(&tbuf, buf, sizeof(tbuf)))
316 return -EFAULT;
317
318 out->uid = tbuf.shm_perm.uid;
319 out->gid = tbuf.shm_perm.gid;
320 out->mode = tbuf.shm_flags;
321
322 return 0;
323 }
324 case IPC_OLD:
325 {
326 struct shmid_ds tbuf_old;
327
328 if (copy_from_user(&tbuf_old, buf, sizeof(tbuf_old)))
329 return -EFAULT;
330
331 out->uid = tbuf_old.shm_perm.uid;
332 out->gid = tbuf_old.shm_perm.gid;
333 out->mode = tbuf_old.shm_flags;
334
335 return 0;
336 }
337 default:
338 return -EINVAL;
339 }
340}
341
342static inline unsigned long copy_shminfo_to_user(void __user *buf, struct shminfo64 *in, int version)
343{
344 switch(version) {
345 case IPC_64:
346 return copy_to_user(buf, in, sizeof(*in));
347 case IPC_OLD:
348 {
349 struct shminfo out;
350
351 if(in->shmmax > INT_MAX)
352 out.shmmax = INT_MAX;
353 else
354 out.shmmax = (int)in->shmmax;
355
356 out.shmmin = in->shmmin;
357 out.shmmni = in->shmmni;
358 out.shmseg = in->shmseg;
359 out.shmall = in->shmall;
360
361 return copy_to_user(buf, &out, sizeof(out));
362 }
363 default:
364 return -EINVAL;
365 }
366}
367
368static void shm_get_stat(unsigned long *rss, unsigned long *swp)
369{
370 int i;
371
372 *rss = 0;
373 *swp = 0;
374
375 for (i = 0; i <= shm_ids.max_id; i++) {
376 struct shmid_kernel *shp;
377 struct inode *inode;
378
379 shp = shm_get(i);
380 if(!shp)
381 continue;
382
383 inode = shp->shm_file->f_dentry->d_inode;
384
385 if (is_file_hugepages(shp->shm_file)) {
386 struct address_space *mapping = inode->i_mapping;
387 *rss += (HPAGE_SIZE/PAGE_SIZE)*mapping->nrpages;
388 } else {
389 struct shmem_inode_info *info = SHMEM_I(inode);
390 spin_lock(&info->lock);
391 *rss += inode->i_mapping->nrpages;
392 *swp += info->swapped;
393 spin_unlock(&info->lock);
394 }
395 }
396}
397
398asmlinkage long sys_shmctl (int shmid, int cmd, struct shmid_ds __user *buf)
399{
400 struct shm_setbuf setbuf;
401 struct shmid_kernel *shp;
402 int err, version;
403
404 if (cmd < 0 || shmid < 0) {
405 err = -EINVAL;
406 goto out;
407 }
408
409 version = ipc_parse_version(&cmd);
410
411 switch (cmd) {
412 case IPC_INFO:
413 {
414 struct shminfo64 shminfo;
415
416 err = security_shm_shmctl(NULL, cmd);
417 if (err)
418 return err;
419
420 memset(&shminfo,0,sizeof(shminfo));
421 shminfo.shmmni = shminfo.shmseg = shm_ctlmni;
422 shminfo.shmmax = shm_ctlmax;
423 shminfo.shmall = shm_ctlall;
424
425 shminfo.shmmin = SHMMIN;
426 if(copy_shminfo_to_user (buf, &shminfo, version))
427 return -EFAULT;
428
429 err= shm_ids.max_id;
430 if(err<0)
431 err = 0;
432 goto out;
433 }
434 case SHM_INFO:
435 {
436 struct shm_info shm_info;
437
438 err = security_shm_shmctl(NULL, cmd);
439 if (err)
440 return err;
441
442 memset(&shm_info,0,sizeof(shm_info));
443 down(&shm_ids.sem);
444 shm_info.used_ids = shm_ids.in_use;
445 shm_get_stat (&shm_info.shm_rss, &shm_info.shm_swp);
446 shm_info.shm_tot = shm_tot;
447 shm_info.swap_attempts = 0;
448 shm_info.swap_successes = 0;
449 err = shm_ids.max_id;
450 up(&shm_ids.sem);
451 if(copy_to_user (buf, &shm_info, sizeof(shm_info))) {
452 err = -EFAULT;
453 goto out;
454 }
455
456 err = err < 0 ? 0 : err;
457 goto out;
458 }
459 case SHM_STAT:
460 case IPC_STAT:
461 {
462 struct shmid64_ds tbuf;
463 int result;
464 memset(&tbuf, 0, sizeof(tbuf));
465 shp = shm_lock(shmid);
466 if(shp==NULL) {
467 err = -EINVAL;
468 goto out;
469 } else if(cmd==SHM_STAT) {
470 err = -EINVAL;
471 if (shmid > shm_ids.max_id)
472 goto out_unlock;
473 result = shm_buildid(shmid, shp->shm_perm.seq);
474 } else {
475 err = shm_checkid(shp,shmid);
476 if(err)
477 goto out_unlock;
478 result = 0;
479 }
480 err=-EACCES;
481 if (ipcperms (&shp->shm_perm, S_IRUGO))
482 goto out_unlock;
483 err = security_shm_shmctl(shp, cmd);
484 if (err)
485 goto out_unlock;
486 kernel_to_ipc64_perm(&shp->shm_perm, &tbuf.shm_perm);
487 tbuf.shm_segsz = shp->shm_segsz;
488 tbuf.shm_atime = shp->shm_atim;
489 tbuf.shm_dtime = shp->shm_dtim;
490 tbuf.shm_ctime = shp->shm_ctim;
491 tbuf.shm_cpid = shp->shm_cprid;
492 tbuf.shm_lpid = shp->shm_lprid;
493 if (!is_file_hugepages(shp->shm_file))
494 tbuf.shm_nattch = shp->shm_nattch;
495 else
496 tbuf.shm_nattch = file_count(shp->shm_file) - 1;
497 shm_unlock(shp);
498 if(copy_shmid_to_user (buf, &tbuf, version))
499 err = -EFAULT;
500 else
501 err = result;
502 goto out;
503 }
504 case SHM_LOCK:
505 case SHM_UNLOCK:
506 {
507
508
509
510 if (!capable(CAP_IPC_LOCK)) {
511 err = -EPERM;
512 goto out;
513 }
514
515 shp = shm_lock(shmid);
516 if(shp==NULL) {
517 err = -EINVAL;
518 goto out;
519 }
520 err = shm_checkid(shp,shmid);
521 if(err)
522 goto out_unlock;
523
524 err = security_shm_shmctl(shp, cmd);
525 if (err)
526 goto out_unlock;
527
528 if(cmd==SHM_LOCK) {
529 if (!is_file_hugepages(shp->shm_file))
530 shmem_lock(shp->shm_file, 1);
531 shp->shm_flags |= SHM_LOCKED;
532 } else {
533 if (!is_file_hugepages(shp->shm_file))
534 shmem_lock(shp->shm_file, 0);
535 shp->shm_flags &= ~SHM_LOCKED;
536 }
537 shm_unlock(shp);
538 goto out;
539 }
540 case IPC_RMID:
541 {
542
543
544
545
546
547
548
549
550
551
552 down(&shm_ids.sem);
553 shp = shm_lock(shmid);
554 err = -EINVAL;
555 if (shp == NULL)
556 goto out_up;
557 err = shm_checkid(shp, shmid);
558 if(err)
559 goto out_unlock_up;
560
561 if (current->euid != shp->shm_perm.uid &&
562 current->euid != shp->shm_perm.cuid &&
563 !capable(CAP_SYS_ADMIN)) {
564 err=-EPERM;
565 goto out_unlock_up;
566 }
567
568 err = security_shm_shmctl(shp, cmd);
569 if (err)
570 goto out_unlock_up;
571
572 if (shp->shm_nattch){
573 shp->shm_flags |= SHM_DEST;
574
575 shp->shm_perm.key = IPC_PRIVATE;
576 shm_unlock(shp);
577 } else
578 shm_destroy (shp);
579 up(&shm_ids.sem);
580 goto out;
581 }
582
583 case IPC_SET:
584 {
585 if (copy_shmid_from_user (&setbuf, buf, version)) {
586 err = -EFAULT;
587 goto out;
588 }
589 down(&shm_ids.sem);
590 shp = shm_lock(shmid);
591 err=-EINVAL;
592 if(shp==NULL)
593 goto out_up;
594 err = shm_checkid(shp,shmid);
595 if(err)
596 goto out_unlock_up;
597 err=-EPERM;
598 if (current->euid != shp->shm_perm.uid &&
599 current->euid != shp->shm_perm.cuid &&
600 !capable(CAP_SYS_ADMIN)) {
601 goto out_unlock_up;
602 }
603
604 err = security_shm_shmctl(shp, cmd);
605 if (err)
606 goto out_unlock_up;
607
608 shp->shm_perm.uid = setbuf.uid;
609 shp->shm_perm.gid = setbuf.gid;
610 shp->shm_flags = (shp->shm_flags & ~S_IRWXUGO)
611 | (setbuf.mode & S_IRWXUGO);
612 shp->shm_ctim = get_seconds();
613 break;
614 }
615
616 default:
617 err = -EINVAL;
618 goto out;
619 }
620
621 err = 0;
622out_unlock_up:
623 shm_unlock(shp);
624out_up:
625 up(&shm_ids.sem);
626 goto out;
627out_unlock:
628 shm_unlock(shp);
629out:
630 return err;
631}
632
633
634
635
636
637
638
639
640long do_shmat(int shmid, char __user *shmaddr, int shmflg, ulong *raddr)
641{
642 struct shmid_kernel *shp;
643 unsigned long addr;
644 unsigned long size;
645 struct file * file;
646 int err;
647 unsigned long flags;
648 unsigned long prot;
649 unsigned long o_flags;
650 int acc_mode;
651 void *user_addr;
652
653 if (shmid < 0) {
654 err = -EINVAL;
655 goto out;
656 } else if ((addr = (ulong)shmaddr)) {
657 if (addr & (SHMLBA-1)) {
658 if (shmflg & SHM_RND)
659 addr &= ~(SHMLBA-1);
660 else
661#ifndef __ARCH_FORCE_SHMLBA
662 if (addr & ~PAGE_MASK)
663#endif
664 return -EINVAL;
665 }
666 flags = MAP_SHARED | MAP_FIXED;
667 } else {
668 if ((shmflg & SHM_REMAP))
669 return -EINVAL;
670
671 flags = MAP_SHARED;
672 }
673
674 if (shmflg & SHM_RDONLY) {
675 prot = PROT_READ;
676 o_flags = O_RDONLY;
677 acc_mode = S_IRUGO;
678 } else {
679 prot = PROT_READ | PROT_WRITE;
680 o_flags = O_RDWR;
681 acc_mode = S_IRUGO | S_IWUGO;
682 }
683
684
685
686
687
688 shp = shm_lock(shmid);
689 if(shp == NULL) {
690 err = -EINVAL;
691 goto out;
692 }
693 err = shm_checkid(shp,shmid);
694 if (err) {
695 shm_unlock(shp);
696 goto out;
697 }
698 if (ipcperms(&shp->shm_perm, acc_mode)) {
699 shm_unlock(shp);
700 err = -EACCES;
701 goto out;
702 }
703
704 err = security_shm_shmat(shp, shmaddr, shmflg);
705 if (err) {
706 shm_unlock(shp);
707 return err;
708 }
709
710 file = shp->shm_file;
711 size = i_size_read(file->f_dentry->d_inode);
712 shp->shm_nattch++;
713 shm_unlock(shp);
714
715 down_write(¤t->mm->mmap_sem);
716 if (addr && !(shmflg & SHM_REMAP)) {
717 user_addr = ERR_PTR(-EINVAL);
718 if (find_vma_intersection(current->mm, addr, addr + size))
719 goto invalid;
720
721
722
723
724 if (addr < current->mm->start_stack &&
725 addr > current->mm->start_stack - size - PAGE_SIZE * 5)
726 goto invalid;
727 }
728
729 user_addr = (void*) do_mmap (file, addr, size, prot, flags, 0);
730
731invalid:
732 up_write(¤t->mm->mmap_sem);
733
734 down (&shm_ids.sem);
735 if(!(shp = shm_lock(shmid)))
736 BUG();
737 shp->shm_nattch--;
738 if(shp->shm_nattch == 0 &&
739 shp->shm_flags & SHM_DEST)
740 shm_destroy (shp);
741 else
742 shm_unlock(shp);
743 up (&shm_ids.sem);
744
745 *raddr = (unsigned long) user_addr;
746 err = 0;
747 if (IS_ERR(user_addr))
748 err = PTR_ERR(user_addr);
749out:
750 return err;
751}
752
753
754
755
756
757asmlinkage long sys_shmdt(char __user *shmaddr)
758{
759 struct mm_struct *mm = current->mm;
760 struct vm_area_struct *vma, *next;
761 unsigned long addr = (unsigned long)shmaddr;
762 loff_t size = 0;
763 int retval = -EINVAL;
764
765 down_write(&mm->mmap_sem);
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787 vma = find_vma(mm, addr);
788
789 while (vma) {
790 next = vma->vm_next;
791
792
793
794
795
796
797 if ((vma->vm_ops == &shm_vm_ops || is_vm_hugetlb_page(vma)) &&
798 (vma->vm_start - addr)/PAGE_SIZE == vma->vm_pgoff) {
799
800
801 size = vma->vm_file->f_dentry->d_inode->i_size;
802 do_munmap(mm, vma->vm_start, vma->vm_end - vma->vm_start);
803
804
805
806
807
808
809 retval = 0;
810 vma = next;
811 break;
812 }
813 vma = next;
814 }
815
816
817
818
819
820
821 while (vma && (loff_t)(vma->vm_end - addr) <= size) {
822 next = vma->vm_next;
823
824
825 if ((vma->vm_ops == &shm_vm_ops || is_vm_hugetlb_page(vma)) &&
826 (vma->vm_start - addr)/PAGE_SIZE == vma->vm_pgoff)
827
828 do_munmap(mm, vma->vm_start, vma->vm_end - vma->vm_start);
829 vma = next;
830 }
831
832 up_write(&mm->mmap_sem);
833 return retval;
834}
835
836#ifdef CONFIG_PROC_FS
837static int sysvipc_shm_read_proc(char *buffer, char **start, off_t offset, int length, int *eof, void *data)
838{
839 off_t pos = 0;
840 off_t begin = 0;
841 int i, len = 0;
842
843 down(&shm_ids.sem);
844 len += sprintf(buffer, " key shmid perms size cpid lpid nattch uid gid cuid cgid atime dtime ctime\n");
845
846 for(i = 0; i <= shm_ids.max_id; i++) {
847 struct shmid_kernel* shp;
848
849 shp = shm_lock(i);
850 if(shp!=NULL) {
851#define SMALL_STRING "%10d %10d %4o %10u %5u %5u %5d %5u %5u %5u %5u %10lu %10lu %10lu\n"
852#define BIG_STRING "%10d %10d %4o %21u %5u %5u %5d %5u %5u %5u %5u %10lu %10lu %10lu\n"
853 char *format;
854
855 if (sizeof(size_t) <= sizeof(int))
856 format = SMALL_STRING;
857 else
858 format = BIG_STRING;
859 len += sprintf(buffer + len, format,
860 shp->shm_perm.key,
861 shm_buildid(i, shp->shm_perm.seq),
862 shp->shm_flags,
863 shp->shm_segsz,
864 shp->shm_cprid,
865 shp->shm_lprid,
866 is_file_hugepages(shp->shm_file) ? (file_count(shp->shm_file) - 1) : shp->shm_nattch,
867 shp->shm_perm.uid,
868 shp->shm_perm.gid,
869 shp->shm_perm.cuid,
870 shp->shm_perm.cgid,
871 shp->shm_atim,
872 shp->shm_dtim,
873 shp->shm_ctim);
874 shm_unlock(shp);
875
876 pos += len;
877 if(pos < offset) {
878 len = 0;
879 begin = pos;
880 }
881 if(pos > offset + length)
882 goto done;
883 }
884 }
885 *eof = 1;
886done:
887 up(&shm_ids.sem);
888 *start = buffer + (offset - begin);
889 len -= (offset - begin);
890 if(len > length)
891 len = length;
892 if(len < 0)
893 len = 0;
894 return len;
895}
896#endif
897