澄清乙個get user pages的事實

2021-09-11 06:44:21 字數 3361 閱讀 1189

分享一下我老師大神的人工智慧教程。零基礎!通俗易懂!風趣幽默!還帶黃段子!希望你也加入到我們人工智慧的隊伍中來!

get_user_pages的作用是得到使用者的頁面,作為引數返回,注意,得到的是乙個page結構陣列而不是別的,這些page最起碼 在當前記錄著使用者程序的資料,一般情況下,核心在呼叫此函式得到使用者頁面以後,會再將它們對映到核心空間的乙個虛擬位址,然後操作這些頁面的資料。這樣的話在呼叫完get_user_pages之後然後對映到核心的的頁面就最少在兩個地方有對映,乙個是使用者空間,乙個是核心空間。這時問題出來了,這些頁面可能會被換出,get_user_pages並沒有做任何事情比如鎖住頁面以保證頁面不被換出,在頁面換出的時候,使用者對映的頁表項的存在位會被清除,但是這可能不會通知該頁面的核心對映的頁表項,如果核心繼續讀寫該頁面,那麼結果將是錯誤的,因此,核心不應該長時間的保持get_user_pages的對映,請看下面的例子,在2.6核心的aio中:  

...   

info->nr_pages = get_user_pages(current, ctx->mm, info->mmap_base, nr_pages, 1, 0, info->ring_pages, null);   

up_write(&ctx->mm->mmap_sem);   

if (unlikely(info->nr_pages != nr_pages))    

ctx->user_id = info->mmap_base;  //比如執行到這裡的時候該程序被搶占,ring_pages[0]被換出,下面的就會是不正確的。(注釋1)   

info->nr = nr_events;           /* trusted copy 呵呵,這裡的注釋很有意思*/   

ring = kmap_atomic(info->ring_pages[0], km_user0);  //對映之後,快速拷貝資料   

ring->nr = nr_events;   /* user copy */   

ring->id = ctx->user_id;   

ring->head = ring->tail = 0;   

ring->magic = aio_ring_magic;   

ring->compat_features = aio_ring_compat_features;   

ring->incompat_features = aio_ring_incompat_features;   

ring->header_length = sizeof(struct aio_ring);   

kunmap_atomic(ring, km_user0);  //馬上解除對映,將出錯的機會降低到最小   

...   

注 釋1的意思很明顯,雖然在get_user_pages中可能呼叫get_page增加了頁面的引用計數,但是請記住,引用計數的增加僅僅是推遲了頁面換 出並沒有阻止頁面的換出,因為在**的時候會put_page_testzero以減少計數,get_page增加了頁面的引用計數只是說明這個頁面「最 近被使用」過,這在lru中被探測。這個告誡到此為止。   

核心的設計者之所以沒有按照完全完美的方式設計上述**是因為核心極端複雜,很多行為已經不再是確定性的了,而更多意義上是一種統計性行為,在億萬分之一的出錯機率下,如果在損失效能以求完備和最大化效能優勢從而冒險二者當中選一的話,百分之九十九的人會選擇後者...

分享一下我老師大神的人工智慧教程。零基礎!通俗易懂!風趣幽默!還帶黃段子!希望你也加入到我們人工智慧的隊伍中來!

get_user_pages的作用是得到使用者的頁面,作為引數返回,注意,得到的是乙個page結構陣列而不是別的,這些page最起碼 在當前記錄著使用者程序的資料,一般情況下,核心在呼叫此函式得到使用者頁面以後,會再將它們對映到核心空間的乙個虛擬位址,然後操作這些頁面的資料。這樣的話在呼叫完get_user_pages之後然後對映到核心的的頁面就最少在兩個地方有對映,乙個是使用者空間,乙個是核心空間。這時問題出來了,這些頁面可能會被換出,get_user_pages並沒有做任何事情比如鎖住頁面以保證頁面不被換出,在頁面換出的時候,使用者對映的頁表項的存在位會被清除,但是這可能不會通知該頁面的核心對映的頁表項,如果核心繼續讀寫該頁面,那麼結果將是錯誤的,因此,核心不應該長時間的保持get_user_pages的對映,請看下面的例子,在2.6核心的aio中:  

...   

info->nr_pages = get_user_pages(current, ctx->mm, info->mmap_base, nr_pages, 1, 0, info->ring_pages, null);   

up_write(&ctx->mm->mmap_sem);   

if (unlikely(info->nr_pages != nr_pages))    

ctx->user_id = info->mmap_base;  //比如執行到這裡的時候該程序被搶占,ring_pages[0]被換出,下面的就會是不正確的。(注釋1)   

info->nr = nr_events;           /* trusted copy 呵呵,這裡的注釋很有意思*/   

ring = kmap_atomic(info->ring_pages[0], km_user0);  //對映之後,快速拷貝資料   

ring->nr = nr_events;   /* user copy */   

ring->id = ctx->user_id;   

ring->head = ring->tail = 0;   

ring->magic = aio_ring_magic;   

ring->compat_features = aio_ring_compat_features;   

ring->incompat_features = aio_ring_incompat_features;   

ring->header_length = sizeof(struct aio_ring);   

kunmap_atomic(ring, km_user0);  //馬上解除對映,將出錯的機會降低到最小   

...   

注 釋1的意思很明顯,雖然在get_user_pages中可能呼叫get_page增加了頁面的引用計數,但是請記住,引用計數的增加僅僅是推遲了頁面換 出並沒有阻止頁面的換出,因為在**的時候會put_page_testzero以減少計數,get_page增加了頁面的引用計數只是說明這個頁面「最 近被使用」過,這在lru中被探測。這個告誡到此為止。   

核心的設計者之所以沒有按照完全完美的方式設計上述**是因為核心極端複雜,很多行為已經不再是確定性的了,而更多意義上是一種統計性行為,在億萬分之一的出錯機率下,如果在損失效能以求完備和最大化效能優勢從而冒險二者當中選一的話,百分之九十九的人會選擇後者...

澄清一些概念

參考 以前一直分不清 authentication 和 authorization,其實很簡單,舉個例子來說 你要登機,你需要出示你的 passport 和 ticket,passport 是為了證明你張三確實是你張三,這就是 authentication 而機票是為了證明你張三確實買了票可以上飛機...

乙個決定,乙個轉折

距離2012年9月已經是第四個年頭,對於我,我想這是我這輩子做的第一件我很自豪,很開心的乙個決定,從生物轉向計算機,一直以來,我對自己的期望總是很高,比如說上高中的時候,希望自己至少考個二本,學習個自己喜歡的專業,然後為之奮鬥,有乙個非常激動人心的大學四年,再比如說以後賺很多很多錢,擁有屬於自己的公...

乙個建築挽救乙個城市

熊大尋創意建築設計公司認為 中國城市化和城市建設浪潮前所未有地吸引了史上最多的外國建築大師湧入中國。中國各大城市充滿了欲與天公試比高的高樓大廈。一幢幢玻璃大廈拔地而起,一座座奇形怪狀的建築安家東方大地。在這場城市建設的洋務運動中,中國市民不僅失去了自己的熟悉的故宅家園,更重要的是身邊越來越多看不懂的...