前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Linux | 内存分配之malloc->brk

Linux | 内存分配之malloc->brk

作者头像
heidsoft
发布2023-03-18 17:17:05
1.7K0
发布2023-03-18 17:17:05
举报

~/Downloads/research/linux-5.15.4/mm/mmap.c

代码语言:javascript
复制
SYSCALL_DEFINE1(brk, unsigned long, brk)
{
  unsigned long newbrk, oldbrk, origbrk;
  struct mm_struct *mm = current->mm;
  struct vm_area_struct *next;
  unsigned long min_brk;
  bool populate;
  bool downgraded = false;
  LIST_HEAD(uf);

  if (mmap_write_lock_killable(mm))
    return -EINTR;

  origbrk = mm->brk;

#ifdef CONFIG_COMPAT_BRK
  /*
   * CONFIG_COMPAT_BRK can still be overridden by setting
   * randomize_va_space to 2, which will still cause mm->start_brk
   * to be arbitrarily shifted
   */
  if (current->brk_randomized)
    min_brk = mm->start_brk;
  else
    min_brk = mm->end_data;
#else
  min_brk = mm->start_brk;
#endif
  if (brk < min_brk)
    goto out;

  /*
   * Check against rlimit here. If this check is done later after the test
   * of oldbrk with newbrk then it can escape the test and let the data
   * segment grow beyond its set limit the in case where the limit is
   * not page aligned -Ram Gupta
   */
  if (check_data_rlimit(rlimit(RLIMIT_DATA), brk, mm->start_brk,
            mm->end_data, mm->start_data))
    goto out;

  newbrk = PAGE_ALIGN(brk);
  oldbrk = PAGE_ALIGN(mm->brk);
  if (oldbrk == newbrk) {
    mm->brk = brk;
    goto success;
  }

  /*
   * Always allow shrinking brk.
   * __do_munmap() may downgrade mmap_lock to read.
   */
  if (brk <= mm->brk) {
    int ret;

    /*
     * mm->brk must to be protected by write mmap_lock so update it
     * before downgrading mmap_lock. When __do_munmap() fails,
     * mm->brk will be restored from origbrk.
     */
    mm->brk = brk;
    ret = __do_munmap(mm, newbrk, oldbrk-newbrk, &uf, true);
    if (ret < 0) {
      mm->brk = origbrk;
      goto out;
    } else if (ret == 1) {
      downgraded = true;
    }
    goto success;
  }

  /* Check against existing mmap mappings. */
  next = find_vma(mm, oldbrk);
  if (next && newbrk + PAGE_SIZE > vm_start_gap(next))
    goto out;

  /* Ok, looks good - let it rip. */
  if (do_brk_flags(oldbrk, newbrk-oldbrk, 0, &uf) < 0)
    goto out;
  mm->brk = brk;

success:
  populate = newbrk > oldbrk && (mm->def_flags & VM_LOCKED) != 0;
  if (downgraded)
    mmap_read_unlock(mm);
  else
    mmap_write_unlock(mm);
  userfaultfd_unmap_complete(mm, &uf);
  if (populate)
    mm_populate(oldbrk, newbrk - oldbrk);
  return brk;

out:
  mmap_write_unlock(mm);
  return origbrk;
}
代码语言:javascript
复制
/*
 *  this is really a simplified "do_mmap".  it only handles
 *  anonymous maps.  eventually we may be able to do some
 *  brk-specific accounting here.
 */
static int do_brk_flags(unsigned long addr, unsigned long len, unsigned long flags, struct list_head *uf)
{
  struct mm_struct *mm = current->mm;
  struct vm_area_struct *vma, *prev;
  struct rb_node **rb_link, *rb_parent;
  pgoff_t pgoff = addr >> PAGE_SHIFT;
  int error;
  unsigned long mapped_addr;

  /* Until we need other flags, refuse anything except VM_EXEC. */
  if ((flags & (~VM_EXEC)) != 0)
    return -EINVAL;
  flags |= VM_DATA_DEFAULT_FLAGS | VM_ACCOUNT | mm->def_flags;

  mapped_addr = get_unmapped_area(NULL, addr, len, 0, MAP_FIXED);
  if (IS_ERR_VALUE(mapped_addr))
    return mapped_addr;

  error = mlock_future_check(mm, mm->def_flags, len);
  if (error)
    return error;

  /* Clear old maps, set up prev, rb_link, rb_parent, and uf */
  if (munmap_vma_range(mm, addr, len, &prev, &rb_link, &rb_parent, uf))
    return -ENOMEM;

  /* Check against address space limits *after* clearing old maps... */
  if (!may_expand_vm(mm, flags, len >> PAGE_SHIFT))
    return -ENOMEM;

  if (mm->map_count > sysctl_max_map_count)
    return -ENOMEM;

  if (security_vm_enough_memory_mm(mm, len >> PAGE_SHIFT))
    return -ENOMEM;

  /* Can we just expand an old private anonymous mapping? */
  vma = vma_merge(mm, prev, addr, addr + len, flags,
      NULL, NULL, pgoff, NULL, NULL_VM_UFFD_CTX);
  if (vma)
    goto out;

  /*
   * create a vma struct for an anonymous mapping
   */
  vma = vm_area_alloc(mm);
  if (!vma) {
    vm_unacct_memory(len >> PAGE_SHIFT);
    return -ENOMEM;
  }

  vma_set_anonymous(vma);
  vma->vm_start = addr;
  vma->vm_end = addr + len;
  vma->vm_pgoff = pgoff;
  vma->vm_flags = flags;
  vma->vm_page_prot = vm_get_page_prot(flags);
  vma_link(mm, vma, prev, rb_link, rb_parent);
out:
  perf_event_mmap(vma);
  mm->total_vm += len >> PAGE_SHIFT;
  mm->data_vm += len >> PAGE_SHIFT;
  if (flags & VM_LOCKED)
    mm->locked_vm += (len >> PAGE_SHIFT);
  vma->vm_flags |= VM_SOFTDIRTY;
  return 0;
}
  • https://www.man7.org/linux/man-pages/man2/brk.2.html
  • https://corey.tech/DevOps-Industry-Updates-1/
  • https://jgsun.github.io/2019/01/21/linux-tcpdump/
  • https://zgqallen.github.io/2019/05/14/linux-glic-mm-overview/
  • https://www.freesion.com/article/87121104152/
  • https://codereview.stackexchange.com/questions/80190/malloc-free-realloc-using-brk-and-sbrk
  • https://www.kernel.org/doc/html/latest/core-api/memory-allocation.html
本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2022-11-22,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 云数智圈 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
相关产品与服务
CODING DevOps
CODING DevOps 一站式研发管理平台,包括代码托管、项目管理、测试管理、持续集成、制品库等多款产品和服务,涵盖软件开发从构想到交付的一切所需,使研发团队在云端高效协同,实践敏捷开发与 DevOps,提升软件交付质量与速度。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档