Problem with deleting directories on NFS in FreeBSD

Problem with deleting directories on NFS in FreeBSD

Marcin K.發表於
Number of replies: 3

Hi,

I've tried to open issue on https://tracker.moodle.org/ but the system does not want to accept it 傷心 So I've decided to open topic on this forum. Maybe someone will find the problem important.

We have moodle installation on FreeBSD and recently we moved moodledata to NFS. After this we observed a problem with deleting directories from moodle.

I've started a topic on FreeBSD Forums: Problem wiith removing folders on NFS

The conclusion from the discusion is that this is definitely a problem of NFS client in FreeBSD but it can be solved at the Moodle's side. I think safely and system independently.

The essence of the problem is that directory handle changes while the entries are enumarated and deleted one by one. So one of the proposed solutions from the mentioned FreeBSD Forums topic was: list the directory content to the memory first and then delete all entries.

So I changed in moodlelib.php the contents of remove_dir function.

The originally there was:

    if (!$handle = opendir($dir)) {
        return false;
    }
    $result = true;
    while (false!==($item = readdir($handle))) {
        if ($item != '.' && $item != '..') {
            if (is_dir($dir.'/'.$item)) {
                $result = remove_dir($dir.'/'.$item) && $result;
            } else {
                $result = unlink($dir.'/'.$item) && $result;
            }
        }
    }

    closedir($handle);

I changed this to:

    if (!$handle = opendir($dir)) {
        return false;
    }
    $result = true;
    // First list all files in the directory ...
    $dirlist = [];
    while (false!==($item = readdir($handle))) {
        $dirlist[] = $item;
    }
    closedir($handle);
    // ... then delete all elements
    foreach ($dirlist as &$item) {
        if ($item != '.' && $item != '..') {
            if (is_dir($dir.'/'.$item)) {
                $result = remove_dir($dir.'/'.$item) && $result;
            } else {
                $result = unlink($dir.'/'.$item) && $result;
            }
        }
    }
    // Clear variables from memory...
    unset($item);
    unset($dirlist);

And it seems to work properly.

Can this change or similar (I'm not a professional PHP programmer) be included in the main Moodle code?

Regards,
Marcin


評比平均分數:Useful (1)
In reply to Marcin K.

Re: Problem with deleting directories on NFS in FreeBSD

Tim Hunt發表於
Core developers的相片 Documentation writers的相片 Particularly helpful Moodlers的相片 Peer reviewers的相片 Plugin developers的相片
That second implementation seems more prone to race conditions, if two separate requests try to manipulate the same folder.
In reply to Tim Hunt

Re: Problem with deleting directories on NFS in FreeBSD

Marcin K.發表於

Earlier in the remove_dir function we have:

    if (!$contentonly) {
        // Start by renaming the directory; this will guarantee that other processes don't write to it
        // while it is in the process of being deleted.
        $tempdir = rename_to_unused_name($dir);
        if ($tempdir) {
            // If the rename was successful then delete the $tempdir instead.
            $dir = $tempdir;
        }
        // If the rename fails, we will continue through and attempt to delete the directory
        // without renaming it since that is likely to at least delete most of the files.
    }

So if my solution is more prone to race conditions - I'm not sure, because some kind of race conditions pushed mi to make mofifications in moodlelib.php - maybe good solution is use my version in directory was renemed succesfully and original version otherwise?