Kernel read process for seq_file files

Source: Internet
Author: User
from:http://www.cnblogs.com/wandererzj/archive/2012/04/16/2452209.html kernel read process for seq_file files

1 questions
Seq_file simply adds the kernel buffering function to the normal file read, allowing sequential traversal to read the simple interface of large data volumes. Seq_file generally only provides read-only interface, in the use of seq_file operation, mainly by the following four operations to complete the kernel custom buffer traversal output operation, where the POS as a traversal iterator, in the Seq_read function is used multiple times, To locate the current position currently read from the kernel custom linked list, POS is important when multiple reads, and POS always follows the order of traversal from 0,1,2...end+1, which must be used as a subscript for traversing the kernel custom list or as an identity for the returned content. But I only use it as the return content of the indicator, and did not use it as the index to traverse the list, resulting in a large number of return data caused a strange strange error, note: Start returns the Void*v if not 0, after the show output, after being passed as a parameter to the next function, Next can be modified or ignored, and when next or start returns NULL, control the path to Seq_end in Seq_open.

struct Seq_operations {
    void * (*start) (struct seq_file *m, loff_t *pos);
    void (*stop) (struct seq_file *m, void *v);
    void * (*next) (struct seq_file *m, void *v, loff_t *pos);
    Int (*show) (struct seq_file *m, void *v);
};

2 Seq_file Operation details
2.0 struct Seq_file Structure description

struct Seq_file {
    char *buf;       Allocated in Seq_open, 4KB
    size_t size;     4096
    size_t from;     The offset address size_t count of the buf when the struct file is copied from Seq_file to the user-state buffer
    ;    The number of characters that can be copied to the user state
    loff_t index;    The subscript POS value for the processing of start and next from the kernel state to the Seq_file kernel buffer buf, i.e. the user-defined traversal of the ITER
    loff_t read_pos;//The amount of data currently copied to the user state, that is, the struct The amount of data copied to the user state in file
    u64 version; 
    struct mutex lock; The mutex structure that protects the seq_file
    const struct seq_operations *op;//seq_start,seq_next,set_show,seq_stop function struct body
    void * private;
};
* Color for custom kernel buffer with Seq_file kernel
-seq_file kernel buffer relative to user-state buffer

2.1 Common file The Open function of struct files establishes the connection relationship between struct file Seq_file seq_file and struct seq_operation operation function.

/** * seq_open-initialize Sequential file * @file: File We Initialize * @op: Method Table describing  The sequence * * Seq_open () sets @file, associating it with a sequence described * by @op. @op->start () sets the iterator up and returns the first * element of sequence.  @op->stop () shuts it down.  @op->next () * Returns the next element of sequence.  @op->show () prints element * into the buffer.  In case of error->start () and->next () return * ERR_PTR (Error). In the end of sequence they return%null.
 ->show () * Returns 0 in case of success and negative number in case of error.
* Returning Seq_skip means "discard this element and move on". If there is a problem with initialization: Start,next returns ERR_PTR If there is a problem at the end: When return null is displayed correctly at the end of the Traverse, show returns 0 and returns a negative value if an error is displayed */
int seq_open (struct file *file, const struct seq_operations *op) {struct Seq_file *p = file->private_data;
        if (!p) {p = kmalloc (sizeof (*P), Gfp_kernel);
        if (!p) Return-enomem;
    File->private_data = p;
    } memset (p, 0, sizeof (*p));
    Mutex_init (&p->lock);

    P->op = op; /* * Wrappers around seq_open (e.g. Swaps_open) need to IS * aware of this.
     If They set f_version themselves, they * should call Seq_open first and then set F_version.

    */file->f_version = 0;  /* * Seq_files support Lseek () and Pread ().
     They does not implement * write () at all, but we clear fmode_pwrite here for historical * reasons. * * If a client of Seq_files a) implements File.write () and B) wishes to * Support Pwrite () then that client wil
     L need to implement it own * File.Open () which calls Seq_open () and then sets Fmode_pwrite. */File->f_mode &= ~fmode_pwrite;
return 0; } export_symbol (Seq_open);

2.2 Normal File The read function of struct files is Seq_read, complete the seq_file reading process
Under normal circumstances two times completed: The first execution of Seq_read: Start->show->next->show...->next->show->next->stop, This returns the kernel custom buffer, which is copied!=0, so there will be a second read operation
Second execution of Seq_read: Because the kernel customizations are returned at this time, according to the Seq_file->index instructions, execute start->stop, return 0, that is copied=0, and exit the Seq_read operation
Overall, the user state calls a read operation, the seq_file process is: the function calls the struct seq_operations struct order is:start->show->next->show...->next-> Show->next->stop->start->stop to read sequential files

  1/** 2 * seq_read-->read () method for sequential files. 3 * @file: The file to read from 4 * @buf: The buffer to read to 5 * @size: The maximum number of bytes to read 6 * @ppos: The current position in the file 7 * 8 * ready-made->f_op->read () 9 */ssize_t seq_read (struct fil e *file, Char __user *buf, size_t size, loff_t *ppos) One {a struct seq_file *m = (struct seq_file *) File->priva
 Te_data;
 size_t copied = 0;
 loff_t POS;
 size_t N;
 *p void;
 + int err = 0;
 Mutex_lock (&m->lock); */* Don ' t assume *ppos is where we left it * * if (unlikely (*ppos! = M->read_pos))//If the user has read the content and Seq_
 File inconsistency, to discard seq_file part of the content m->read_pos = *ppos; (Err = Traverse (M, *ppos)) = =-eagain)//If so, first through seq_start,seq_show,seq_next,seq_show...seq_next,seq_s
 How,seq_stop read *pos size content to Seq_file BUF 26; if (Err) 28 {29            /* with prejudice ... */m->read_pos = 0;
 m->version = 0;
 M->index = 0;
 M->count = 0;
 Goto done; * * * * SEQ_FILE->OP->      M_start/m_stop/m_next may does special actions 41 * or optimisations based on the file->f_version.
 * Pass the file->f_version to those methods. * Seq_file->version is just copy of F_version, and seq_file * methods can treat it simply as F
 Ile version.
 * It's copied in first and copied out after all operations. * It is convenient to has it as part of structure to avoid the * need of passing another argument-all t
 He seq_file methods.
 */m->version = file->f_version; Grab buffer If we didn ' t have one */Wuyi if (!M->BUF) if first read seq_file, apply 4K size space >buf = Kmalloc (m->siZe = page_size, gfp_kernel);
 if (!m->buf)-Goto Enomem; +/-/If not empty-flush it first * * * if (m->count)///If there is already content in Seq_file, you may have tested some of the content in front of Traverse 5
 9 {n = min (m->count, size); Err = Copy_to_user (buf, M->buf + M->from, n);
 Copy to User state if (err) Efault Goto;
 M->count-= n;
 M->from + = n;
 size = N;
 BUF + = n;
 copied + = n;
 if (!m->count)//If the count byte is copied exactly through the seq_ sequence operation, starting at the next position, it is not clear that the M->index has been added in the Traverse function, and it should be added here.
 m->index++;
 if (!size) goto done;              * */We need at least one record in buffer */m->index; pos =   Assuming that the function starts here, pos=0, when the second execution, pos = The last subscript of the last traversal + 1 >0, so in Start, the POS is required for a non 0 special handling of the P = M->op->start (M, &pos); P is the string pointer returned by Seq_start, pos=0; 1) Ptr_err (P); if (!p | |
 Is_err (P))//If through start or next traversal error, that is, return p error, exit the loop, generally, at the second Seq_open, through start that error [POS change], exit the loop Bayi break;   M->op->show err = n/A (m, p);             Displays the contents of p to the BUF buffer of the seq_file structure if (Err < 0)//If an error occurs via show output, exiting the loop, this indicates that BUF has overflowed 84
 Break             if (unlikely (ERR))///if Seq_show returns to normal [i.e. seq_file buf not overflow, returns 0], at which time M->count is set to 0, M->count is set to 0 86   
 M->count = 0; if (unlikely (!m->count))//general, m->count==0, so the decision returns false, #define unlikely (x) __builtin_expect (!!
 (x), 0) for branch prediction, to improve the system water efficiency. {p = m->op->next (M, p, &pos);
 M->index = pos;
 Continue; (M->count < M->size)//Normally, after seq_start->seq_s How to get here [basically this is the case], or in err.
 =0 [i.e. show error] && M->count! = 0 o'clock Get here 94 goto Fill; M->op->sTop (M, p);
 Kfree (M-&GT;BUF);
 M->buf = Kmalloc (m->size <<= 1, Gfp_kernel);
98 if (!m->buf) goto Enomem;
M->count = 0;
101 m->version = 0;
102 pos = m->index;
103 p = M->op->start (M, &pos);   104} m->op->stop (M, p);
Normally, entering here, all the seq_file files have been copied to buf, and buf not overflow, which indicates that the SEQ serialization operation returned less content, less than 4KB 106 M->count = 0;
107 Goto Done; 108 fill:109/* They want more?          
Let's try to get some more * * (M->count < size) 111 {size_t offs = m->count;
113 loff_t next = pos;   p = M->op->next (M, p, &next); In the general case, only the Seq_start and Seq_show functions are experienced in the while loop above, and then enter here, in this loop, the following loop is executed: if (!p | |                               Is_err (P))//If Seq_file's buf is not full: seq_next,seq_show,.... seq_next-> Jump 116 {

If the Seq_file buf is full: The offs represents the maximum amount of reads before the full, and P returns a pointer to the custom structure content, but later show can only copy the


117 err = Ptr_err (p);
Part of the content, resulting in m->cont = = M->size judgment established, thus m->count rollback to this copy, the back of the pos++ said next from the next start copy 118 break;   119} + Err = M->op->show (M, p); //I encountered the actual problem is show after the direct to stop, so quit from here, should be seq_file buf fill caused the problem, here must be m->count = = M->size121 if (M->count = = M->size | | err)//Seq_file buf full: seq_next,seq_show,.... seq_next,seq_show-> Jump 122         {123 M->count = offs; 124 if (likely (Err <= 0)) break; 126
} 127 pos = next;     129 M->op->stop (M, p);
The last execution of the Seq_stop function is n = min (m->count, size); 131 err = Copy_to_user (buf, M-&GT;BUF, N);
Copies the kernel buffer contents of up to size to the user-state buffer buf if (ERR) 133 goto efault;
134 copied + = N;
135 M->count-= n; 136 if (M->count) if the user state is not copied, such as Seq_file count=100, but n=10, that is, copy the first 10, the next time from the 10-bit copy, this situation generally does not appear 137 M->from
= N; 138 Else//In general, pos++, next traversal from next start, the beginning, let SEQ_FUNC traversal pointer decrement, but each time with K exit, the next continue to decrement from K, the original is here + +, so the traversal is best to let the pointer increment139 pos++;
M->index = pos;   141 done:142 if (!copied) 143 copied = err; copied = 0 144 else 145 {146 *ppos + = copied; 147 M->read_pos + = copied; 148} 149 F
Ile->f_version = m->version;
Mutex_unlock (&m->lock);   151 return copied;
Returns the number of characters copied and copies the copied characters from the buf of Seq_file to the buf of the user enomem:153 err =-enomem;
154 goto done;
155 efault:156 err =-efault;
157 goto done; 158}
My situation is:
The execution process is: ... next->show-> stop->start-> stop->start->stop, the problem arises because the buf of Seq_file was found to be full during a call to show. At this point M->count back to the call, and then call the Stop function, because the stop content is very small, so you can fill in the Seq_file buf, so that the first fill_buf operation, with the stop information, after the operation, at this time pos= 0, because the seq_read at the end of the + +, resulting in seq_file->index=1, and then the second time into the seq_read, this time may appear err, causing the function to return a non 0, the 3rd time, only return 0.

2.3 Copying data from the custom core into the BUF buffer of the SEQ_FILE structure operator function

 int seq_printf (struct seq_file *m, const char *f, ...)
    {va_list args;

    int Len;
        if (M->count < m->size) {va_start (args, f);
        Len = vsnprintf (M->buf + m->count, M->size-m->count, F, args);
        Va_end (args);
            if (M->count + len < m->size) {m->count + = Len;     return 0;
    Successfully returned 0, at this time buf}} m->count = m->size;   return-1; Returns 1} 
if the BUF buffer is full, or if output to buf causes buf overflow

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.