存档在 2012年1月

从修改文件扩展名到子串删除

2012年1月30日

之前在这篇文章中已经列举了一种通用的批量修改文件后缀名的方法,今天看到变量替换${var%pattern},因此又有下面的一种方法:

#!/bin/bash

if [ $# -ne 3 ]
then
	echo "Usage:$(basename $0) old_name new_name dir"
	exit -1
fi

old_name="$1"
new_name="$2"
dir="$3"

for file in $(ls *.$old_name)
do
	newfile=${file%.$old_name}.$new_name
	mv $file $newfile
	echo "$file ===> $newfile"
done

exit 0

该脚本用到了变量替换中的子串删除方法:${var%pattern}。它的作用是从变量$var的末尾删除最小匹配$pattern字符串。与此对应的方法${var%%pattern}则是删除最大匹配$pattern字串。比如:

edsionte@edsionte-laptop:~/mytest$ var=abcd12345abc6789
edsionte@edsionte-laptop:~/mytest$ pattern=b*9
edsionte@edsionte-laptop:~/mytest$ echo "${var%$pattern}"
abcd12345a
edsionte@edsionte-laptop:~/mytest$ echo "${var%%$pattern}"
a

如果想从变量$var开头删除字符串$pattern,则可以使用${var#pattern}删除最小匹配的字符串,而${var##pattern}则可以删除最大匹配$pattern的字符串。比如:

edsionte@edsionte-laptop:~/mytest$ var=abcd12345abc6789
edsionte@edsionte-laptop:~/mytest$ pattern=a*c
edsionte@edsionte-laptop:~/mytest$ echo "${var#$pattern}"
d12345abc6789
edsionte@edsionte-laptop:~/mytest$ echo "${var##$pattern}"
6789

从变量中删除指定字符串是一种常见的操作。

删除日志文件的经典脚本

2012年1月29日

本文所示的删除/var/log下日志文件脚本源于abs这本书,虽然实际功能只是简单的清空该目录下的messages文件,但是这个脚本具有广义性,可以作为其他脚本的模板。

#!/bin/bash

LOG_DIR=/var/log
ROOT_UID=0
LINES=50
E_XCD=66
E_NOTROOT=67

为了更好的移植性,事先定义几个变量。比如用LOG_DIR指定日志所在目录,E_开头的变量为不同的错误码。

if [ "$UID" -ne "$ROOT_UID" ]
then 
	echo "Must be root to run this script."
	exit $E_NOTROOT
fi

if [ -n "$1" ]
then 
	lines=$1
else
	lines=$LINES
fi

由于删除/var/log下的文件需要root身份,因此一开始先判断运行该脚本的用户是否为root。接着判断参数1是否为空,lines指定默认日志保留的行数。

cd $LOG_DIR

if [ `pwd` != "$LOG_DIR" ]
then
	echo "Can't change to $LOG_DIR."
	exit $E_XCD
fi

判断是否成功进入了LOG_DIR所代表的目录。上述代码的更有效率的表示方法为:

# cd /var/log || {
#   echo "Cannot change to necessary directory." >&2
#   exit $E_XCD;
# }

最后才是实质性的日志删除功能:

tail -$lines messages > mesg.temp
mv mesg.temp messages

exit 0

最后只保留messages文件中lines行日志。

该脚本的功能虽然简单,但是却拥有用户身份检查、参数检查等功能,对其他脚本而言是个很好的模板。

Linux页框分配函数的实现(1)-主体分配函数

2012年1月11日

内核中有六个基本的页框分配函数,它们内部经过封装,最终都会调用alloc_pages_node()。这个函数的参数比alloc_pages()多了一个nid,它用来指定节点id,如果nid小于0,则说明在当前节点上分配页框。正确获取到节点id后,接下来调用__alloc_pages()。

static inline struct page *alloc_pages_node(int nid, gfp_t gfp_mask, unsigned int order)
{
        if (nid < 0)
                nid = numa_node_id();

        return __alloc_pages(gfp_mask, order, node_zonelist(nid, gfp_mask));
}

__alloc_pages()第三个参数根据nid和gfp_mask得到适当的zonelist链表,该过程通过node_zonelist()完成。该函数的实现比较简单,其中NODE_DATA()根据nid返回对应的内存节点描述符,而gfp_zonelist()根据flags标志选取对应的内存管理区链表。其实node_zonelist()就是根据flags在相应内存节点的node_zonelists数组中选择一个何时的内存管理区链表zonelist。

static inline int gfp_zonelist(gfp_t flags)
{
        if (NUMA_BUILD && unlikely(flags & __GFP_THISNODE))
                return 1;

        return 0;
}

由于node_zonelists数组的元素个数最大为2,因此gfp_zonelist()返回0或者1。如果flags中设置了__GFP_THISNODE并且NUMA被设置,则表明使用当前节点对应的zonelist,返回1。否则使用备用zonelist,也就是说当本地节点中zone不足时,在其他节点中申请页框。

static inline int gfp_zonelist(gfp_t flags)
{
        if (NUMA_BUILD && unlikely(flags & __GFP_THISNODE))
                return 1;

        return 0;
}

__alloc_pages()内部再次封装__alloc_pages_nodemask()。

static inline struct page *
__alloc_pages(gfp_t gfp_mask, unsigned int order, struct zonelist *zonelist)
{
        return __alloc_pages_nodemask(gfp_mask, order, zonelist, NULL);
}

1. 主体分配函数

现在进入__alloc_pages_nodemask(),它作为页框分配函数的核心部分。该函数可以通过get_page_from_freelist()快速分配所请求的内存,但是大多数情况下调用该函数都会失败,因为通常物理内存的使用情况都比较紧张,这一点从其后if语句中的unlikely就可以看出。

struct page *
__alloc_pages_nodemask(gfp_t gfp_mask, unsigned int order,struct zonelist *zonelist, nodemask_t *nodemask)
{
        enum zone_type high_zoneidx = gfp_zone(gfp_mask);
        struct zone *preferred_zone;
        struct page *page;
        int migratetype = allocflags_to_migratetype(gfp_mask);

        gfp_mask &= gfp_allowed_mask;

        lockdep_trace_alloc(gfp_mask);

        might_sleep_if(gfp_mask & __GFP_WAIT);

        if (should_fail_alloc_page(gfp_mask, order))
                return NULL; 

        if (unlikely(!zonelist->_zonerefs->zone))
                return NULL;            

        first_zones_zonelist(zonelist, high_zoneidx, nodemask, &preferred_zone);
        if (!preferred_zone)
                return NULL;

        page = get_page_from_freelist(gfp_mask|__GFP_HARDWALL, nodemask, order,
                        zonelist, high_zoneidx, ALLOC_WMARK_LOW|ALLOC_CPUSET,
                        preferred_zone, migratetype);
        if (unlikely(!page))
                page = __alloc_pages_slowpath(gfp_mask, order,
                                zonelist, high_zoneidx, nodemask,
                                preferred_zone, migratetype);

        trace_mm_page_alloc(page, order, gfp_mask, migratetype);
        return page;
}

首先,gfp_zone()根据gfp_mask选取适当类型的zone。在经过几项参数检查后,该函数通过zonelist->_zonerefs->zone判断zonelist是否为空,既至少需要一个zone可用。接着根据一开始选取的zone类型high_zoneidx,通过first_zones_zonelist()确定优先分配内存的内存管理区。

如果一切顺利,将会进入get_page_from_freelist(),这个函数可以看作是伙伴算法的前置函数,它通过分配标志和分配阶判断是否能进行此次内存分配。如果可以分配,则它进行实际的内存分配工作,既利用伙伴算法进行分配内存。否则,进入__alloc_pages_slowpath(),此时内核需要放宽一些分配条件,或回收一些系统的内存,然后再调用几次get_page_from_freelist()以申请所需内存。

请求页框API简介

2012年1月4日

在用户态下程序中,我们可以通过malloc()动态申请内存空间。在内核空间中,专门有一个内核子系统处理对连续页框的内存分配请求,这个内核子系统即为管理区页框分配器(zoned page frame allocator)。该分配器包含六个专门用于分配页框的API,这些API都是基于伙伴算法而实现的,因此这些API申请的页框数只能为2的整数幂大小。

内存分配器API

1.alloc_pages()

该宏用来分配2的order次方个连续的页框,如果申请成功返回第一个所分配页框的描述符地址,申请失败的话返回NULL。

#define alloc_pages(gfp_mask, order) \
                alloc_pages_node(numa_node_id(), gfp_mask, order)

2.alloc_page()

该函数用来分配一个单独的页框,它可以看作是alloc_pages()当order等于0时的特殊情况。

#define alloc_page(gfp_mask) alloc_pages(gfp_mask, 0)

3.__get_free_pages()

通过该函数可以申请长为2的order次方大小的连续页框,但是它返回的是这段连续页框中第一个页所对应的线性地址。从源码中可以看出,该函数内部仍然调用了alloc_pages函数,并利用page_address函数将页描述符地址转换为线性地址。

unsigned long __get_free_pages(gfp_t gfp_mask, unsigned int order)
{
        struct page *page;

        VM_BUG_ON((gfp_mask & __GFP_HIGHMEM) != 0);

        page = alloc_pages(gfp_mask, order);
        if (!page)
                return 0;
        return (unsigned long) page_address(page);
}

4.__get_free_page()

该宏可以看作是__get_free_pages函数的特殊情况,它用于申请一个单独的页框。

#define __get_free_page(gfp_mask) \
        __get_free_pages((gfp_mask),0)

5.get_zeroed_page()

该函数用来获取一个填满0的页框,其中__GFP_ZERO参数用来体现这一点。

unsigned long get_zeroed_page(gfp_t gfp_mask)
{
        return __get_free_pages(gfp_mask | __GFP_ZERO, 0);
}

6.__get_dma_pages()

该宏获得的页框用于DMA操作。

#define (gfp_mask, order) \
                __get_free_pages((gfp_mask) | GFP_DMA,(order))

请求页框的标志

从上述几个分配器API中可以看到,除了用于指示请求页框大小的order参数外,还包括一组标志gfp_mask,它指明了如何寻找空闲的页框。下面仅说明几个常见的分配标志。

__GFP_DMA:该标志指明只能从ZONE_DMA内存管理区获得页框。

__GFP_HIGHMEM:如果该标志被设置,则按照ZONE_HIGHMEM,ZONE_NORMAL和ZONE_DMA的请求顺序获得页框,既首先在ZONE_HIGHMEME区请求所需大小的页框,如果该区无法满足请求页框的大小,则再向ZONE_DMA区发出请求。如果该标志没有被设置,则按照默认的ZONE_NORMAL和ZONE_DMA内存管理区的顺序获取页框。

__GFP_ZERO:如果设置了该标志,那么所申请的页框必须被填满0。

API关系图

本文所介绍的这几个API本质上都调用了alloc_pages(),而alloc_pages()又在其内部调用了alloc_pages_node(),它们之间的关系如下图所示:

从图中可以看出,alloc_pages_node()是所有分配器API的核心函数。

windows 7 ultimate product key

windows 7 ultimate product key

winrar download free

winrar download free

winzip registration code

winzip registration code

winzip free download

winzip free download

winzip activation code

winzip activation code

windows 7 key generator

windows 7 key generator

winzip freeware

winzip freeware

winzip free download full version

winzip free download full version

free winrar download

free winrar download

free winrar

free winrar

windows 7 crack

windows 7 crack

windows xp product key

windows xp product key

windows 7 activation crack

windows7 activation crack

free winzip

free winzip

winrar free download

winrar free download

winrar free

winrar free

download winrar free

download winrar free

windows 7 product key

windows 7 product key