<div>Здравствуйте!<br /><br />> уверены, что этот коммит валиден?<br /><br />Не знаю, насколько это актуальная информация,</div><div>но, как я увидел, коммит касается не только log.c,<br />но и super.c, на всякий случай прикладываю:<br /><a href="https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/fs/gfs2/super.c?id=35264909e9d1973ab9aaa2a1b07cda70f12bb828" rel="noopener noreferrer" target="_blank">https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/fs/gfs2/super.c?id=35264909e9d1973ab9aaa2a1b07cda70f12bb828</a><br /><br />Не понял, как на git.kernel.org открыть коммит<br />целиком, а не по отдельному файлу. Вот также<br />он целиком на другой платформе:<br /><a href="https://patchew.org/linux/20260205044147.1948143-1-black.hawk@163.com/" rel="noopener noreferrer" target="_blank">https://patchew.org/linux/20260205044147.1948143-1-black.hawk@163.com/</a><br /><br />Не знаю, влияет ли это на актуальность ваших</div><div>вопросов, но на всякий случай отправляю.<br /> <div>> стоит изучить, действительно ли возможно</div><div>> состояние гонки, которое он правит:<div>> где зануляется указатель sdp->sd_jdesc</div></div><div><br />Меняется при размонтировании фс в</div><div>put_super: вызывается gfs2_jindex_free(),<br />внутри которой под<br />down_write(&sdp->sd_log_flush_lock) и<br />выставляется NULL:<br />ссылка на вызов gfs2_jindex_free() в<br />put_super():</div><div><div><a href="https://elixir.bootlin.com/linux/v6.1.164/source/fs/gfs2/super.c#L639" rel="noopener noreferrer" target="_blank">https://elixir.bootlin.com/linux/v6.1.164/source/fs/gfs2/super.c#L639</a><br /><br /><br />> Как понимаю, речь идёт об условиях<br />> *условия для вызова log_write_header()*<br />> и почему они не будут выполнены при</div><div>> shutdown? Не ясна связь с log_pull_tail()</div><div>> и gfs2_log_update_head().<br /><br />Перечитал своё письмо, понял, что<br />неаккуратно выразился: при вызове<br />gfs2_log_flush() с флагом</div><div><div>GFS2_LOG_HEAD_FLUSH_SHUTDOWN они</div><div>как раз будут вызваны в последний раз и<br />отработают, как я понимаю, без ошибок.<br /><br />После этого зайдём в gfs2_log_shutdown,<br />который уже вызовет log_write_header()<br />с флагами GFS2_LOG_HEAD_UNMOUNT<br />и GFS2_LFC_SHUTDOWN, а log_pull_tail()<br />и gfs2_log_update_head() обновят указатели<br />из условий, сделая их равными.<br /><br />Ввиду того, что фс уже находится в RO,<br />действия, меняющие эти указатели,<br />не пройдут: в следующей строчке<br />в gfs2_log_flush() при отработке с<br />флагом shutdown из указателя на<br />суперблок убирается флаг<br />SDF_JOURNAL_LIVE:<br /><a href="https://elixir.bootlin.com/linux/v6.1.164/source/fs/gfs2/log.c#L1093" rel="noopener noreferrer" target="_blank">https://elixir.bootlin.com/linux/v6.1.164/source/fs/gfs2/log.c#L1093</a><br /><br />Например, при начале транзакции есть проверка<br />на этот флаг: если его нет, то возвращаем<br />ошибку:<br /><a href="https://elixir.bootlin.com/linux/v6.1.164/source/fs/gfs2/trans.c#L52" rel="noopener noreferrer" target="_blank">https://elixir.bootlin.com/linux/v6.1.164/source/fs/gfs2/trans.c#L52</a><div><br /><br />> Разыменовывание возможно ещё<br />> по метке out_end в функции<br />> log_distance():</div><div>> <a href="https://elixir.bootlin.com/linux/v6.1.164/source/fs/gfs2/log.c#L1143" rel="noopener noreferrer" target="_blank">https://elixir.bootlin.com/linux/v6.1.164/source/fs/gfs2/log.c#L1143</a><br /> </div><div>> Пока предлагаю подробнее изучить<br />> коммит 35264909e9d1 ("gfs2: Fix NULL<br />> pointer dereference in gfs2_log_flush").<br />> Согласны ли с проблемой, которую он правит?</div><br />Ещё раз пройдясь по коду, обратил внимание<br />на упомянутый выше флаг SDF_JOURNAL_LIVE:<br />после перевода фс в ro он будет выставлен<br />при gfs2_log_flush() с флагом shutdown, как,<br />опять же, указал выше.<br /><br />Зануление же указателя sdp->sd_jdesc<br />происходит по коду дальше, чем перевод<br />в только чтение:<br />1) ro:<div><a href="https://elixir.bootlin.com/linux/v6.1.164/source/fs/gfs2/super.c#L603" rel="noopener noreferrer" target="_blank">https://elixir.bootlin.com/linux/v6.1.164/source/fs/gfs2/super.c#L603</a><br />2) обнуление:<br /><a href="https://elixir.bootlin.com/linux/v6.1.164/source/fs/gfs2/super.c#L639" rel="noopener noreferrer" target="_blank">https://elixir.bootlin.com/linux/v6.1.164/source/fs/gfs2/super.c#L639</a><br /><br />Следовательно, если мы имеем нулевой<br />sdp->sd_jdesc в gfs2_log_flush(), то мы<br />тем более имеем и стёртый SDF_JOURNAL_LIVE,<br />а значит, в<br /><a href="https://elixir.bootlin.com/linux/v6.1.164/source/fs/gfs2/log.c#L1051" rel="noopener noreferrer" target="_blank">https://elixir.bootlin.com/linux/v6.1.164/source/fs/gfs2/log.c#L1051</a><br />выйдем по метке out, где разыменования вроде<br />как не будет. То есть вроде как и добавленная в<br />обсуждаемом коммите проверка указателя на<br />NULL в gfs2_log_flush действительно излишняя -<br />либо я что-то упускаю.<br /><br />Укажите, пожалуйста, на недочёты в рассуждениях.<br /><br />Кузнецов Николай</div></div></div></div></div><blockquote><p>On Sat, 11. Apr 15:20, Николай Кузнецов wrote:</p><blockquote>    Здравствуйте! Отправляю исправленную версию<br />    рассуждений по предупреждению анализатора.<br /> <br />    Предупреждение было ошибочным, далее привожу<br />    обоснование.<br />    Согласно коммиту<br />    [1]<a href="https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/fs/gfs2/log.c?id=35264909e9d1973ab9aaa2a1b07cda70f12bb828" rel="noopener noreferrer">https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/fs/gfs2/log.c?id=35264909e9d1973ab9aaa2a1b07cda70f12bb828</a>,<br />    нулевой указатель sdp->sd_jdesc приходит<br />    в gfs2_log_flush в ситуации гонки между<br />    размонтированием файловой системы и<br />    асинхронной обработки glock в workqueue.</blockquote><p><br />Хм, всё же уверены, что этот коммит валиден? Для этого стоит изучить,<br />действительно ли возможно состояние гонки, которое он правит: где<br />зануляется указатель sdp->sd_jdesc и как происходит жизненный цикл<br />работы &gl->gl_work.<br /> </p><blockquote> <br />    Однако при размонтировании журнал<br />    обнуляется уже после переведения фс<br />    в режим readonly и сброса всех изменений<br />    на диск, а задача из очереди вызывает<br />    gfs2_log_flush (по цепочке glock_work_func -><br />    run_queue -> do_xmote -> inode_go_sync -><br />    gfs2_log_flush) без флага<br />    GFS2_LOG_HEAD_FLUSH_NORMAL, а значит,<br />    до gfs2_log_shutdown (стр. 1139 log.c)<br />    исполнение функции просто не дойдёт.</blockquote><p><br />Здесь возможно опечатка. gfs2_log_shutdown() вызывается вроде как раз<br />когда во флагах _не_ выставлен GFS2_LOG_HEAD_FLUSH_NORMAL.<br /> </p><blockquote> <br />    Проблемы с вызовами log_write_header (строки<br />    1111 и 1113) тоже нет, поскольку перед обнулением<br />    журнала вызывается gfs2_log_flush с флагом<br />    GFS2_LOG_HEAD_FLUSH_SHUTDOWN и<br />    из-за вызовов log_pull_tail и gfs2_log_update_head<br />    при размонтировании не будут выполнены<br />    условия в строках 1110 и 1112.</blockquote><p><br />Как понимаю, речь идёт об условиях<br /><br />        if (sdp->sd_log_head != sdp->sd_log_flush_head) {<!-- --><br />                log_write_header(sdp, flags);<br />        } else if (sdp->sd_log_tail != sdp->sd_log_flush_tail && !sdp->sd_log_idle) {<!-- --><br />                log_write_header(sdp, flags);<br />        }<br /><br />и почему они не будут выполнены при shutdown? Не ясна связь с<br />log_pull_tail() и gfs2_log_update_head().<br /><br /><br />Разыменовывание возможно ещё по метке out_end в функции log_distance():<br /><a href="https://elixir.bootlin.com/linux/v6.1.164/source/fs/gfs2/log.c#L1143" rel="noopener noreferrer">https://elixir.bootlin.com/linux/v6.1.164/source/fs/gfs2/log.c#L1143</a><br /><br /><br />Пока предлагаю подробнее изучить коммит 35264909e9d1 ("gfs2: Fix NULL<br />pointer dereference in gfs2_log_flush"). Согласны ли с проблемой,<br />которую он правит?<br /> </p></blockquote>