bug version of munmap

master
forever-learner 2 years ago
parent 3e50ff7954
commit 9465af4e86

@ -19,13 +19,14 @@
* *
* Also corrected some "invalidate()"s - I wasn't doing enough of them. * Also corrected some "invalidate()"s - I wasn't doing enough of them.
*/ */
#include <stdarg.h>
#include <signal.h> #include <signal.h>
#include <asm/system.h> #include <asm/system.h>
#include <linux/sched.h> #include <linux/sched.h>
#include <linux/head.h> #include <linux/head.h>
#include <linux/kernel.h> #include <linux/kernel.h>
#include <new.h>
#include <asm/segment.h>
volatile void do_exit(long code); volatile void do_exit(long code);
static inline volatile void oom(void) static inline volatile void oom(void)
@ -369,8 +370,8 @@ void do_no_page(unsigned long error_code,unsigned long address)
unsigned long page; unsigned long page;
int block,i; int block,i;
if (current->pid > 5) /* if (current->pid > 5)
printk(" --do_no_page: address=%x, pid=%d\n", address, current->pid); printk(" --do_no_page: address=%x, pid=%d\n", address, current->pid); */
address &= 0xfffff000; address &= 0xfffff000;
tmp = address - current->start_code; tmp = address - current->start_code;
@ -466,3 +467,375 @@ void calc_mem(void)
} }
static int my_share(unsigned long address, struct task_struct * p)
{
unsigned long from;
unsigned long to;
unsigned long from_page;
unsigned long to_page;
unsigned long phys_addr;
from_page = to_page = ((address>>20) & 0xffc);
from_page += ((current->start_code>>20) & 0xffc);
to_page += ((p->start_code>>20) & 0xffc);
from = *(unsigned long *) from_page;
from &= 0xfffff000;
from_page = from + ((address>>10) & 0xffc);
phys_addr = *(unsigned long *) from_page;
to = *(unsigned long *) to_page;
if (!(to & 1))
if (to = get_free_page())
*(unsigned long *) to_page = to | 7;
else
return 0;
to &= 0xfffff000;
to_page = to + ((address>>10) & 0xffc);
if (1 & *(unsigned long *) to_page)
return 0;
/* share them: write-protect */
*(unsigned long *) to_page = *(unsigned long *) from_page;
phys_addr -= LOW_MEM;
phys_addr >>= 12;
mem_map[phys_addr]++;
return 1;
}
// rememeber to sync when munmap exit manual
long sys_mmap(void * start,size_t len,...)// int prot,int flags,int fd,off_t off
{
printk("start mmaping\n");
/* va_list args;
va_start(args,len); */
int prot=3,flags=1,fd=3,off=0;
/* prot=va_arg(args,int);flags=va_arg(args,int);fd=va_arg(args,int);
off_t off=va_arg(args,off_t);
int *ll=&len;printk("%d,%d,%d,%d,%d\n",*ll,*(ll+1),*(ll+2),*(ll+3),*(ll+4));
va_end(args);
printk("%d,%d,%d,%ld\n",prot,flags,fd,off);
*/
int block;
size_t l=len;
struct buffer_head * bh;
char *temp,*p1,*p2;
void * buf=start;
int tempprot=0;
//因为new.h和namei.c定义不一样要修改
if(prot &PROT_READ) tempprot |=4;
if(prot &PROT_EXEC) tempprot |=1;
if(prot &PROT_WRITE) tempprot |=2;
//特殊量len>0 off%4096==0 prot至少有read权限
if( (flags & MAP_SHARED)&& (flags &MAP_PRIVATE ))
{
printk("error with private and shared request.\n");
return -1;
}
if(len<=0 || off<0 || (off%PAGE_SIZE))
{
if(len<=0)
printk("the len of the wanting bytes must be positive.\n");
else
printk("offset must be the mul of 4096.\n");
return MAP_FAILED;
}
if(!(prot& PROT_READ)) return MAP_FAILED;
//permissions of the file ,搬运函数namei.c::permissions
printk("fd: %d\n",fd);
struct m_inode *inode=current->filp[fd]->f_inode;
printk("end of permissions\n");
int mode = inode->i_mode;
if (inode->i_dev && !inode->i_nlinks)
{printk("end of permissions1\n");return MAP_FAILED;}
else if (current->euid==inode->i_uid)
mode >>= 6;
else if (current->egid==inode->i_gid)
mode >>= 3;
if (!(((mode & tempprot & 0007) == tempprot) || suser()))
{
printk("error permission.");
return MAP_FAILED;
}
//end of permission check
printk("end of permissions\n");
//设置用户空间的虚拟地址初始为32MB处这样写在brk增长至32MB时会有bug,我们忽略
//同时,当栈向下增长到一定程度时,也会和当前地址冲突,我们忽略
if(start<=current->brk || start>=current->start_stack-0x8000 || start==NULL)
{
if(!current->mmap_tail)
buf=0x2000000;
else
buf=current->mmap_tail->endaddr;
}
//申请mmap
struct mmap_struct *mmap=(struct mmap_struct *)malloc(sizeof(struct mmap_struct));
mmap->address=buf;
mmap->size=len;
mmap->endaddr=(unsigned long)buf+(len + 0xfff)&0xfffff000;
mmap->rw=prot;
mmap->ps=flags;
mmap->filenode=(struct m_inode*)malloc(sizeof(struct m_inode));
memcpy(mmap->filenode,inode,sizeof(struct m_inode));
printk("izone[0]:%x:\n",inode->i_zone[0]);
if(!mmap->filenode->i_count)mmap->filenode->i_count=1;
mmap->off=off;
mmap->next=NULL;
//加入current->mmap
if(!current->mmap)
{current->mmap=current->mmap_tail=mmap;}
else {
current->mmap_tail->next=mmap;
current->mmap_tail=mmap;
}
printk("buf: %x\n",(unsigned long )buf);
//分配物理页
unsigned long from;
unsigned long to;
unsigned long from_page;
unsigned long to_page;
unsigned long phys_addr;
unsigned long tpage;
unsigned long address=mmap->address;
while(address<mmap->endaddr)
{
from_page = ((address>>20) & 0xffc);
from_page += ((current->start_code>>20) & 0xffc);//页目录
if(!(*(unsigned long *)from_page&1)) //页表项不存在,申请页面
if(!(tpage=get_free_page()))
{
printk("out of memory.\n");
return MAP_FAILED;
}
else
{
*(unsigned long *)from_page= tpage | 7;
mem_map[(tpage-LOW_MEM)>>12]++;
}
from=*(unsigned long *)from_page; //页表项
from &= 0xfffff000;
from_page = from + ((address>>10) & 0xffc);
if(!(*(unsigned long *)from_page & 1)) //物理页不存在
if(!(tpage=get_free_page()))
{
printk("out of memory.\n");
return MAP_FAILED;
}
else
{
*(unsigned long *)from_page= tpage | 7;
mem_map[(tpage-LOW_MEM)>>12]++;
}
*(unsigned long *)from_page &= (prot&PROT_WRITE); //分配读写权限
if(flags & MAP_SHARED)
{
printk("i am doing sharing.");
struct task_struct ** p;
for (p = &LAST_TASK ; p > &FIRST_TASK ; --p) {
if (!*p)
continue;
if (current == *p)
continue;
//在这一部分,我将current->address处的物理页复制给
//所有进程的该区域,可能导致错误,但我们忽略。
if(!my_share(address,*p))
printk("share failed at task:pid=%d",(*p)->pid);
}
}
address+=PAGE_SIZE;
}
//read and put in
if (!(block = inode->i_zone[0]))
return NULL;
if (!(bh = bread(inode->i_dev,block)))
return NULL;
temp = (char *) bh->b_data;
p1=temp+off;p2=buf;
while(l--)
put_fs_byte(*(p1++),p2++);
printk("%s\n",temp+off);
return buf;
}
static int my_sync(off_t pos, struct m_inode * inode, char * buf, int count)
{
int block,c;
struct buffer_head * bh;
char * p;
int i=0;
//int block;
//struct buffer_head * bh;
struct dir_entry * de;
int ttp=0;;
printk("sync:izone[0]:%x:\n",inode->i_zone[0]);
if (!(block = inode->i_zone[0]))
return -1;
if (!(bh = bread(inode->i_dev,block)))
return -1;
de=(char*)bh->b_data;
for(ttp=0;ttp<count;ttp++)
{
printk("char:%c,",*(de+ttp));
}
while (i<count) {
if (!(block = create_block(inode,pos/BLOCK_SIZE)))
break;
if (!(bh=bread(inode->i_dev,block)))
break;
c = pos % BLOCK_SIZE;
p = c + bh->b_data;
bh->b_dirt = 1;
c = BLOCK_SIZE-c;
if (c > count-i) c = count-i;
pos += c;
if (pos > inode->i_size) {
inode->i_size = pos;
inode->i_dirt = 1;
}
i += c;
while (c-->0)
*(p++) = get_fs_byte(buf++);
brelse(bh);
}
inode->i_mtime = CURRENT_TIME;//文件最后修改时间
inode->i_ctime = CURRENT_TIME;//i节点修改时间
return (i?i:-1);
}
int sys_munmap(void * start ,size_t size)
{
struct mmap_struct *temp=current->mmap;
struct mmap_struct *pre=NULL;
while(temp!=NULL)
{
if(temp->address==(unsigned long)start)
break;
else temp=temp->next;
pre=temp;
}
if(!temp)
{
printk("invalid address.\n");
return -1;
}
if(!pre)
{
if(current->mmap_tail==current->mmap)current->mmap_tail=NULL;
current->mmap==current->mmap->next;
}
if(temp->next=NULL)
{
current->mmap_tail=pre;
pre->next=NULL;
}
else{
pre->next=temp->next;
}
printk("addr: %lx,endaddr : %lx\n",temp->address,temp->endaddr);
unsigned long from;
unsigned long to;
unsigned long from_page;
unsigned long to_page;
unsigned long phys_addr;
unsigned long tpage;
unsigned long address=temp->address;
if(!(temp->ps & MAP_SHARED))
goto mytag;
//若为共享,执行下面的代码
while (address < temp ->endaddr)
{
printk("addr: %lx\n",address);
from_page = ((address>>20) & 0xffc);
from_page += ((current->start_code>>20) & 0xffc);//页目录
from=*(unsigned long *)from_page; //页表项
from &= 0xfffff000;
from_page = from + ((address>>10) & 0xffc);
phys_addr = (*(unsigned long *)from_page & 0xfffff000);
//printk("addr: %lx",*(unsigned long *)from_page);
if(!(*(unsigned long *)from_page & 1))
{
printk("error of deleting page.");
return -1;
}
if(temp->ps & MAP_SHARED)
{
struct task_struct ** p;
for (p = &LAST_TASK ; p > &FIRST_TASK ; --p) {
if (!*p)
continue;
if (current == *p)
continue;
to_page = ((address>>20) & 0xffc)+(((*p)->start_code>>20) & 0xffc);
to = *(unsigned long *) to_page;
if(!(to & 1))
continue;
to &= 0xfffff000;
to_page = to + ((address>>10) & 0xffc);
if(!(*(unsigned long *)to_page &1))
continue;
to = (*(unsigned long *)to_page & 0xfffff000);
if(phys_addr == to)
{
*(unsigned long *)to_page &= ~1;
mem_map[(phys_addr-LOW_MEM)>>12]--;
}
}
}
address+=PAGE_SIZE;
}
if(temp->ps & MAP_SHARED)
{
if(my_sync(temp->off,temp->filenode,(char*)(temp->address),temp->size)==-1)
return -1;
}
mytag:
//取消物理页写权限
while (address < temp ->endaddr)
{
from_page = ((address>>20) & 0xffc);
from_page += ((current->start_code>>20) & 0xffc);//页目录
from=*(unsigned long *)from_page; //页表项
from &= 0xfffff000;
from_page = from + ((address>>10) & 0xffc);
phys_addr = (*(unsigned long *)from_page & 0xfffff000);
//printk("addr: %lx",*(unsigned long *)from_page);
if(!(*(unsigned long *)from_page & 1))
{
printk("error of deleting page.");
return -1;
}
else{
*(unsigned long *)from_page &= ~1;
}
}
int block;
struct buffer_head * bh;
struct dir_entry * de;
int ttp=0;;
printk("temp->izone[0]:%x:\n",temp->filenode->i_zone[0]);
if (!(block = temp->filenode->i_zone[0]))
return -1;
if (!(bh = bread(temp->filenode->i_dev,block)))
return -1;
de=(char*)bh->b_data;
for(ttp=0;ttp<temp->size;ttp++)
{
printk("char:%c,",*(de+ttp));
}
free(temp);
return 0;
}

Loading…
Cancel
Save