2

Usually proc entries are deleting inside function with __exit attribute. How can I delete it on user request? I've tired to call remove_proc_entry inside write callback, but the kernel crushes there. I cannot just remove module as it manages several proc entries at a time. I'm just want to delete that one for whom i'm telling "delete".

static int my_write(struct file *file, const char __user *userbuff,                                                                                                                                                                                                             
                    size_t len, loff_t *ppos)                                                                                                                                                                                                                                   
{                                                                                                                                                                                                                                                                               
        struct  seq_file *seqf = file->private_data;                                                                                                                                                                                                                             
        struct *my_data = seqf->private;                                                                                                                                                                                                                                        
        char   *buff;                                                                                                                                                                                                                                                            
        int     retval;                                                                                                                                                                                                                                                          
                                                                                                                                                                                                                                                                                
        retval = -EINVAL;                                                                                                                                                                                                                                                       
                                                                                                                                                                                                                                                                                
        if (!userbuff || len > PAGE_SIZE)                                                                                                                                                                                                                                       
                return -EINVAL;                                                                                                                                                                                                                                                 
                                                                                                                                                                                                                                                                                
        buff = kzalloc((len + 1), GFP_KERNEL);                                                                                                                                                                                                                                  
        if (!buff)                                                                                                                                                                                                                                                              
                return -ENOMEM;                                                                                                                                                                                                                                                 
                                                                                                                                                                                                                                                                                
        if (copy_from_user(buff, userbuff, len))                                                                                                                                                                                                                                
                goto out;                                                                                                                                                                                                                                                       
                                                                                                                                                                                                                                                                                
        buff[len] = '\0';                                                                                                                                                                                                                                                       
                                                                                                                                                                                                                                                                                
        if (!strncmp("delete", buff, 6)) {                                                                                                                                                                                                                                      
                /* Cannot use remove_proc_entry inside that write callback. */                                                                                                                                                                                                  
                retval = 0;                                                                                                                                                                                                                                                     
        }                                                                                                                                                                                                                                                                       
                                                                                                                                                                                                                                                                                
        if (!retval)                                                                                                                                                                                                                                                            
                retval = len;                                                                                                                                                                                                                                                   
        else                                                                                                                                                                                                                                                                    
                printk("Usage: echo delete > /proc/my_proc to delete that entry.\n");                                                                                                                                                                                          
                                                                                                                                                                                                                                                                                
        return retval;                                                                                                                                                                                                                                                          
}                                                                                                                                                                                                                                                                               
                                                                                                                                                                                                                                                                                
static const struct file_operations my_proc_fops = {                                                                                                                                                                                                                            
        .open    = my_proc_open,                                                                                                                                                                                                                                                
        .read    = seq_read,                                                                                                                                                                                                                                                    
        .write   = my_write,                                                                                                                                                                                                                                                    
        .llseek  = seq_lseek,                                                                                                                                                                                                                                                   
        .release = single_release,                                                                                                                                                                                                                                              
};  
  • I'm not sure this is possible. You would probably want there to be an `unlink` handler in `struct proc_ops`, so the user could delete the entry with `rm`, [but there isn't one](https://github.com/torvalds/linux/blob/master/include/linux/proc_fs.h). Certainly you can't delete the entry while you're in the write handler for it. – Nate Eldredge Apr 12 '21 at 22:09
  • You could write an `ioctl` (e.g. `MY_PROC_IOCTL_DELETE`) to mark [in your private `struct`] that you want to delete it. At the `release` callback, you could probably delete it there [unlink the directory entry via `remove_proc_entry` or `proc_remove`, etc] – Craig Estey Apr 12 '21 at 22:53
  • 1
    You could statically declare a work item that calls a function to remove the proc item. Then, to delete the proc file, call `schedule_work` with a pointer to the work item. It should result in the function being called sometime soon with a different context. In your module exit function, call `flush_pending_work` in case the scheduled work hasn't been run yet. – Ian Abbott Apr 13 '21 at 16:26

1 Answers1

1

Thanks! I've made it via schedule_work.

struct my_data {
    /* data */
    struct work_struct remove_proc_work;
};

static void remove_proc_work_handler(struct work_struct *work)                                                                                                                                                                                                                  
{                                                                                                                                                                                                                                                                               
        struct my_data *data;                                                                                                                                                                                                                                                  
                                                                                                                                                                                                                                                                                
        data = container_of(work, struct my_data, remove_proc_work);                                                                                                                                                                                                           
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                            
        /* call remove_proc_entry */                                                                                                                                                                                                                                     
} 

static void init_data(struct my_data *data)
{
    /* init data */
    INIT_WORK(&data->remove_proc_work, remove_proc_work_handler);
}

static int my_write(struct file *file, const char __user *userbuff,                                                                                                                                                                                                             
                    size_t len, loff_t *ppos)                                                                                                                                                                                                                                   
{                                                                                                                                                                                                                                                                               
        struct  seq_file *seqf = file->private_data;                                                                                                                                                                                                                             
        struct my_data *data = seqf->private;                                                                                                                                                                                                                                        
        char   *buff;                                                                                                                                                                                                                                                            
        int     retval;                                                                                                                                                                                                                                                          
                                                                                                                                                                                                                                                                                
        retval = -EINVAL;                                                                                                                                                                                                                                                       
                                                                                                                                                                                                                                                                                
        if (!userbuff || len > PAGE_SIZE)                                                                                                                                                                                                                                       
                return -EINVAL;                                                                                                                                                                                                                                                 
                                                                                                                                                                                                                                                                                
        buff = kzalloc((len + 1), GFP_KERNEL);                                                                                                                                                                                                                                  
        if (!buff)                                                                                                                                                                                                                                                              
                return -ENOMEM;                                                                                                                                                                                                                                                 
                                                                                                                                                                                                                                                                                
        if (copy_from_user(buff, userbuff, len))                                                                                                                                                                                                                                
                goto out;                                                                                                                                                                                                                                                       
                                                                                                                                                                                                                                                                                
        buff[len] = '\0';                                                                                                                                                                                                                                                       
                                                                                                                                                                                                                                                                                
        if (!strncmp("delete", buff, 6)) {                                                                                                                                                                                                                                      
                /* Cannot use remove_proc_entry inside that write callback. */                          
                schedule_work(&data->remove_proc_work);                                                                                                                                                       
                retval = 0;                                                                                                                                                                                                                                                     
        }                                                                                                                                                                                                                                                                       
                                                                                                                                                                                                                                                                                
        if (!retval)                                                                                                                                                                                                                                                            
                retval = len;                                                                                                                                                                                                                                                   
        else                                                                                                                                                                                                                                                                    
                printk("Usage: echo delete > /proc/my_proc to delete that entry.\n");                                                                                                                                                                                          
                                                                                                                                                                                                                                                                                
        return retval;                                                                                                                                                                                                                                                          
}                                                                                                                                                                                                                                                                               
                                                                                                                                                                                                                                                                                
static const struct file_operations my_proc_fops = {                                                                                                                                                                                                                            
        .open    = my_proc_open,                                                                                                                                                                                                                                                
        .read    = seq_read,                                                                                                                                                                                                                                                    
        .write   = my_write,                                                                                                                                                                                                                                                    
        .llseek  = seq_lseek,                                                                                                                                                                                                                                                   
        .release = single_release,                                                                                                                                                                                                                                              
};