www.久久久久|狼友网站av天堂|精品国产无码a片|一级av色欲av|91在线播放视频|亚洲无码主播在线|国产精品草久在线|明星AV网站在线|污污内射久久一区|婷婷综合视频网站

當(dāng)前位置:首頁 > 嵌入式 > 嵌入式軟件
[導(dǎo)讀]做內(nèi)核開發(fā)的朋友,可能對下面的代碼都很眼熟。 1. static const struct file_operations xxx_fops = {2. .owner = THIS_MODULE,3. .llseek = no_llseek,4. .write = xxx_w

做內(nèi)核開發(fā)的朋友,可能對下面的代碼都很眼熟。

 

1. static const struct file_operations xxx_fops = {

2. .owner = THIS_MODULE,

3. .llseek = no_llseek,

4. .write = xxx_write,

5. .unlocked_ioctl = xxx_ioctl,

6. .open = xxx_open,

7. .release = xxx_release,

8. };

一般我們在xxx_open中會用類似如下的代碼分配一塊內(nèi)存。

[cpp] view plain copy

1. file->private_data = kmalloc(sizeof(struct xxx), GFP_KERNEL);

然后在接下來的read/write/ioctl中,我們就可以通過file->private_data取到與此文件關(guān)聯(lián)的數(shù)據(jù)。

最后,在xxx_release中,我們會釋放file->private_data指向的內(nèi)存。

如果只是上面這幾種流程訪問file->private_data所指向的數(shù)據(jù),基本上不會出問題。

因為內(nèi)核的文件系統(tǒng)框架已經(jīng)做了很完善的處理。

對于迸發(fā)訪問,我們自己也可以通過鎖等機制來解決。

然而,我們通常還會在一些異步的流程中訪問file->private_data所指向的數(shù)據(jù),這些異步流程可能由定時器,中斷,進程間通信等因素觸發(fā)。

并且,這些流程訪問數(shù)據(jù)時,沒有經(jīng)過內(nèi)核的文件系統(tǒng)框架。

那么這就有可能導(dǎo)致出現(xiàn)問題了。

下面我們先來看看內(nèi)核文件系統(tǒng)框架的部分實現(xiàn)代碼,再來考慮如何規(guī)避可能出現(xiàn)的問題。我們的分析基于linux-3.10.102的內(nèi)核源碼。

首先,要得到一個fd,必須先有一次調(diào)用C庫函數(shù)open的行為。而在C庫函數(shù)open返回之前,其他線程得不到fd,當(dāng)然也就不會對此fd進行操作。等拿到fd時,open操作都已經(jīng)完成了。

實際上,更夸張的情況還是有可能存在的。例如,可能由于程序的錯誤甚至是程序員故意構(gòu)造特殊代碼,導(dǎo)致在open返回之前,其他線程就使用即將返回的fd進行文件操作了。這種情況,這里就不討論了。有興趣的朋友,可以自己鉆研內(nèi)核代碼,看看會產(chǎn)生什么效果。

先看看文件打開操作的主要函數(shù)調(diào)用:

sys_open, do_sys_open, do_filp_open, fd_install, __fd_install。

安裝fd的操作如下。可見這里是對文件表加了鎖的,并且不是針對單個文件,是整體性的加鎖。

[cpp] view plain copy

1. void __fd_install(struct files_struct *files, unsigned int fd,

2. struct file *file)

3. {

4. struct fdtable *fdt;

5. spin_lock(&files->file_lock);

6. fdt = files_fdtable(files);

7. BUG_ON(fdt->fd[fd] != NULL);

8. rcu_assign_pointer(fdt->fd[fd], file);

9. spin_unlock(&files->file_lock);

10. }

讀寫操作,代碼結(jié)構(gòu)非常相似。這里只看寫操作吧。其實現(xiàn)如下:

[cpp] view plain copy

1. SYSCALL_DEFINE3(write, unsigned int, fd, const char __user *, buf,

2. size_t, count)

3. {

4. struct fd f = fdget(fd);

5. ssize_t ret = -EBADF;

6.

7. if (f.file) {

8. loff_t pos = file_pos_read(f.file);

9. ret = vfs_write(f.file, buf, count, &pos);

10. file_pos_write(f.file, pos);

11. fdput(f);

12. }

13.

14. return ret;

15. }

[cpp] view plain copy

1. ssize_t vfs_write(struct file *file, const char __user *buf, size_t count, loff_t *pos)

2. {

3. ssize_t ret;

4.

5. if (!(file->f_mode & FMODE_WRITE))

6. return -EBADF;

7. if (!file->f_op || (!file->f_op->write && !file->f_op->aio_write))

8. return -EINVAL;

9. if (unlikely(!access_ok(VERIFY_READ, buf, count)))

10. return -EFAULT;

11.

12. ret = rw_verify_area(WRITE, file, pos, count);

13. if (ret >= 0) {

14. count = ret;

15. file_start_write(file);

16. if (file->f_op->write)

17. ret = file->f_op->write(file, buf, count, pos);

18. else

19. ret = do_sync_write(file, buf, count, pos);

20. if (ret > 0) {

21. fsnotify_modify(file);

22. add_wchar(current, ret);

23. }

24. inc_syscw(current);

25. file_end_write(file);

26. }

27.

28. return ret;

29. }

[cpp] view plain copy

1. ssize_t do_sync_write(struct file *filp, const char __user *buf, size_t len, loff_t *ppos)

2. {

3. struct iovec iov = { .iov_base = (void __user *)buf, .iov_len = len };

4. struct kiocb kiocb;

5. ssize_t ret;

6.

7. init_sync_kiocb(&kiocb, filp);

8. kiocb.ki_pos = *ppos;

9. kiocb.ki_left = len;

10. kiocb.ki_nbytes = len;

11.

12. ret = filp->f_op->aio_write(&kiocb, &iov, 1, kiocb.ki_pos);

13. if (-EIOCBQUEUED == ret)

14. ret = wait_on_sync_kiocb(&kiocb);

15. *ppos = kiocb.ki_pos;

16. return ret;

17. }

可以看出,讀寫操作是無鎖的。也不好加鎖,因為讀寫操作,還有ioctl,有可能阻塞。如果需要鎖,用戶自己可以使用文件鎖,《UNIX環(huán)境高級編程》中有關(guān)于文件鎖的描述。

不過fdget與fdput中包含了一些rcu方面的操作,那是為了能夠與close fd的操作迸發(fā)進行。[!--empirenews.page--]

另外,可以看出,如果只實現(xiàn)一個f_op->aio_write,也是可以支持C庫函數(shù)write的。

再來看看ioctl的實現(xiàn)。

[cpp] view plain copy

1. SYSCALL_DEFINE3(ioctl, unsigned int, fd, unsigned int, cmd, unsigned long, arg)

2. {

3. int error;

4. struct fd f = fdget(fd);

5.

6. if (!f.file)

7. return -EBADF;

8. error = security_file_ioctl(f.file, cmd, arg);

9. if (!error)

10. error = do_vfs_ioctl(f.file, fd, cmd, arg);

11. fdput(f);

12. return error;

13. }

對于非常規(guī)文件,或者常規(guī)文件中文件系統(tǒng)特有的命令,最終都會走到

filp->f_op->unlocked_ioctl

另外,ioctl也是無鎖的。同時,流程中包含了fdget與fdput,這一點與read/write一樣。

再來看看關(guān)閉文件的操作。系統(tǒng)調(diào)用sys_close的實現(xiàn)如下(fs/open.c)

[cpp] view plain copy

1. SYSCALL_DEFINE1(close, unsigned int, fd)

2. {

3. int retval = __close_fd(current->files, fd);

4.

5. /* can‘t restart close syscall because file table entry was cleared */

6. if (unlikely(retval == -ERESTARTSYS ||

7. retval == -ERESTARTNOINTR ||

8. retval == -ERESTARTNOHAND ||

9. retval == -ERESTART_RESTARTBLOCK))

10. retval = -EINTR;

11.

12. return retval;

13. }

可見主要工作是__close_fd函數(shù)(fs/file.c)完成的,其代碼如下??梢娝菍M程的文件表加了鎖的。因此,open、close操作是有互斥的,并且不是針對某一文件的互斥,而是整體的互斥。

對于close一個fd時,其他cpu上的線程若正要或正在讀寫此fd怎么辦?可以看出,close操作并不會為此等待,而是直接繼續(xù)操作。

其中的rcu_assign_pointer(fdt->fd[fd], NULL);清除了此fd與file結(jié)構(gòu)的關(guān)聯(lián),因此在此之后通過此fd已經(jīng)訪問不到相應(yīng)的file結(jié)構(gòu)了。至于在此之前就發(fā)起了的且尚未結(jié)束的訪問怎么處理,答案是在filp_close中處理。

[cpp] view plain copy

1. int __close_fd(struct files_struct *files, unsigned fd)

2. {

3. struct file *file;

4. struct fdtable *fdt;

5.

6. spin_lock(&files->file_lock);

7. fdt = files_fdtable(files);

8. if (fd >= fdt->max_fds)

9. goto out_unlock;

10. file = fdt->fd[fd];

11. if (!file)

12. goto out_unlock;

13. rcu_assign_pointer(fdt->fd[fd], NULL);

14. __clear_close_on_exec(fd, fdt);

15. __put_unused_fd(files, fd);

16. spin_unlock(&files->file_lock);

17. return filp_close(file, files);

18.

19. out_unlock:

20. spin_unlock(&files->file_lock);

21. return -EBADF;

22. }

filp_close又調(diào)用了fput, 后者的相關(guān)代碼如下??梢姰?dāng)前任務(wù)若非內(nèi)核線程,接下來就是走_(dá)___fput,否則就是走delayed_fput。

但是最終都是走_(dá)_fput,__fput中會調(diào)用file->f_op->release,即我們的xxx_release。

不過,從fput代碼可以看出,____fput會由rcu相關(guān)的work觸發(fā)。因此,可以預(yù)見當(dāng)____fput被調(diào)用時,已經(jīng)沒有已經(jīng)發(fā)生且尚未結(jié)束的針對此文件的訪問流程了。

[cpp] view plain copy

1. static void ____fput(struct callback_head *work)

2. {

3. __fput(container_of(work, struct file, f_u.fu_rcuhead));

4. }

5.

6.

7. void flush_delayed_fput(void)

8. {

9. delayed_fput(NULL);

10. }

11.

12. static DECLARE_WORK(delayed_fput_work, delayed_fput);

13.

14. void fput(struct file *file)

15. {

16. if (atomic_long_dec_and_test(&file->f_count)) {

17. struct task_struct *task = current;

18.

19. if (likely(!in_interrupt() && !(task->flags & PF_KTHREAD))) {

20. init_task_work(&file->f_u.fu_rcuhead, ____fput);

21. if (!task_work_add(task, &file->f_u.fu_rcuhead, true))

22. return;

23. }

24.

25. if (llist_add(&file->f_u.fu_llist, &delayed_fput_list))

26. schedule_work(&delayed_fput_work);

27. }

28. }

現(xiàn)在再來想想,我們上面提到的那些訪問file->private_data所指向的數(shù)據(jù)的異步流程,這些流程并沒有走文件系統(tǒng)框架。

會不會出現(xiàn)這種情況,xxx_release已經(jīng)執(zhí)行過了,可是異步流程卻還來訪問file->private_data所指向的數(shù)據(jù)呢?

其實xxx_release不妨不要釋放file->private_data指向的內(nèi)存,而是標(biāo)記一下他的狀態(tài)為已關(guān)閉。然后異步流程再訪問此數(shù)據(jù)時,先檢查一下狀態(tài)。

若為已關(guān)閉,則妥善處理并釋放即可。

本站聲明: 本文章由作者或相關(guān)機構(gòu)授權(quán)發(fā)布,目的在于傳遞更多信息,并不代表本站贊同其觀點,本站亦不保證或承諾內(nèi)容真實性等。需要轉(zhuǎn)載請聯(lián)系該專欄作者,如若文章內(nèi)容侵犯您的權(quán)益,請及時聯(lián)系本站刪除。
換一批
延伸閱讀

9月2日消息,不造車的華為或?qū)⒋呱龈蟮莫毥谦F公司,隨著阿維塔和賽力斯的入局,華為引望愈發(fā)顯得引人矚目。

關(guān)鍵字: 阿維塔 塞力斯 華為

加利福尼亞州圣克拉拉縣2024年8月30日 /美通社/ -- 數(shù)字化轉(zhuǎn)型技術(shù)解決方案公司Trianz今天宣布,該公司與Amazon Web Services (AWS)簽訂了...

關(guān)鍵字: AWS AN BSP 數(shù)字化

倫敦2024年8月29日 /美通社/ -- 英國汽車技術(shù)公司SODA.Auto推出其旗艦產(chǎn)品SODA V,這是全球首款涵蓋汽車工程師從創(chuàng)意到認(rèn)證的所有需求的工具,可用于創(chuàng)建軟件定義汽車。 SODA V工具的開發(fā)耗時1.5...

關(guān)鍵字: 汽車 人工智能 智能驅(qū)動 BSP

北京2024年8月28日 /美通社/ -- 越來越多用戶希望企業(yè)業(yè)務(wù)能7×24不間斷運行,同時企業(yè)卻面臨越來越多業(yè)務(wù)中斷的風(fēng)險,如企業(yè)系統(tǒng)復(fù)雜性的增加,頻繁的功能更新和發(fā)布等。如何確保業(yè)務(wù)連續(xù)性,提升韌性,成...

關(guān)鍵字: 亞馬遜 解密 控制平面 BSP

8月30日消息,據(jù)媒體報道,騰訊和網(wǎng)易近期正在縮減他們對日本游戲市場的投資。

關(guān)鍵字: 騰訊 編碼器 CPU

8月28日消息,今天上午,2024中國國際大數(shù)據(jù)產(chǎn)業(yè)博覽會開幕式在貴陽舉行,華為董事、質(zhì)量流程IT總裁陶景文發(fā)表了演講。

關(guān)鍵字: 華為 12nm EDA 半導(dǎo)體

8月28日消息,在2024中國國際大數(shù)據(jù)產(chǎn)業(yè)博覽會上,華為常務(wù)董事、華為云CEO張平安發(fā)表演講稱,數(shù)字世界的話語權(quán)最終是由生態(tài)的繁榮決定的。

關(guān)鍵字: 華為 12nm 手機 衛(wèi)星通信

要點: 有效應(yīng)對環(huán)境變化,經(jīng)營業(yè)績穩(wěn)中有升 落實提質(zhì)增效舉措,毛利潤率延續(xù)升勢 戰(zhàn)略布局成效顯著,戰(zhàn)新業(yè)務(wù)引領(lǐng)增長 以科技創(chuàng)新為引領(lǐng),提升企業(yè)核心競爭力 堅持高質(zhì)量發(fā)展策略,塑強核心競爭優(yōu)勢...

關(guān)鍵字: 通信 BSP 電信運營商 數(shù)字經(jīng)濟

北京2024年8月27日 /美通社/ -- 8月21日,由中央廣播電視總臺與中國電影電視技術(shù)學(xué)會聯(lián)合牽頭組建的NVI技術(shù)創(chuàng)新聯(lián)盟在BIRTV2024超高清全產(chǎn)業(yè)鏈發(fā)展研討會上宣布正式成立。 活動現(xiàn)場 NVI技術(shù)創(chuàng)新聯(lián)...

關(guān)鍵字: VI 傳輸協(xié)議 音頻 BSP

北京2024年8月27日 /美通社/ -- 在8月23日舉辦的2024年長三角生態(tài)綠色一體化發(fā)展示范區(qū)聯(lián)合招商會上,軟通動力信息技術(shù)(集團)股份有限公司(以下簡稱"軟通動力")與長三角投資(上海)有限...

關(guān)鍵字: BSP 信息技術(shù)
關(guān)閉
關(guān)閉