lseek method implementation
In this article, let’s implement the lseek method.
In the lseek method, as we explored in the previous article, you should take a decision according to the value of whence information. Whence could SEEK_SET, SEEK_CUR, or SEEK_END.
Let’s use the switch statement, switch(whence), and the first case(as shown below) would be let’s use SEEK_SET. If it is SEEK_SET, then you should set the current file position to the offset. That’s why let’s get the file position from our file pointer. Let’s dereference this pointer, and let’s get the value of file position is equal to offset. And after that break.
loff_t pcd_lseek(struct file *filp, loff_t offset, int whence) { pr_info("lseek requested \n"); switch(whence) { case SEEK_SET: filp->f_pos = offset; break; }
First case SEEK_SET
Let’s implement the second case, SEEK_CUR, as shown in Figure 2. You have to seek from the current file position. That is the meaning of seek from cursor. Basically, you should be doing file position += offset. After that break.
case SEEK_CUR: filp->f_pos += offset; break;
Second case SEEK_CUR
Third case SEEK_END. You should seek from the end of the device. File pointer of f_pos= DEV_MEM_SIZE + offset. Seek from the end, isn’t it? This is a end, and from there you have to seek. And after that Break.
case SEEK_END: filp->f_pos = DEV_MEM_SIZE + offset; break; default: return -EINVAL; } return filp->f_pos; }
Third case SEEK_END
What is the default case?
And if the whence value is something different from these values, then we have to return an error code.
For the lseek system call, you can see that all these could be the error values shown in Figure 1.
If it is EBADF, then that means it’s a bad file descriptor. EINVAL that means whence is not valid. Or: the resulting file offset could be negative or beyond end of a seekable device. This condition, we should take care in our code beyond the end of the seekable device. Because our’s device is nothing but a memory buffer an array. We should not seek beyond that array. If that happens, then it could be a problem.
Our kernel module may crash, or the whole system can crash because we will be touching some memory location, which should not be modified or which should not be accessed. That’s why seeking beyond end of device must be taken care in our code.
What will be doing now is, let’s go back. If it is default.
In the default case, let’s return – EINVAL; Saying that, invalid argument is received for whence. And you have to return the updated a new file position.
Let’s take care of these operations. Because these operations may lead to seeking beyond our device. That’s why let’s put some conditions here. For SEEK_SET, let’s put some conditions as shown in Figure 2. If offset is greater than DEV_MEM_SIZE. Or let’s put that in parentheses, or if offset is less than 0. Then we cannot take that offsets. I would return EINVAL.
How about SEEK_CUR(as shown in Figure 3)?
Here also, you should take care of seeking beyond device. Let me create a temporary variable. And first, let’s calculate the final value of file operation of the file position by adding offset to that. Let me do file position + offset. If temp > DEV_MEM_SIZE or if (temp < 0), then we cannot take that value. I would return -EINVAL here as well. And I would remove this code. Otherwise, I would take that value. I would equate the current file position is equal to temp.
I am calculating the seeking here with respect to the current file position and then checking the final value. That final value should not cross this value, and it should not be less than 0. Only then I would take that value, and I update the current file position.
After that, in the SEEK_END(as shown in Figure 4) again, let’s calculate the temp value. And after that, I think we should reuse as SEEK_CUR.
Here, temp is equal to you should seek from the end. End means DEV_MEM_SIZE. Seek from the end, and if the final value of the temp is greater than DEV_MEM_SIZE or if it is less than zero, then don’t take that return – EINVAL. Otherwise, you can take that value temp. So, that makes sense. Let’s create this temp variable inside pcd_lseek. The data type must be of this one loff_t temp.
Let’s give some print messages, as shown in Figure 5. I would write pr_info “current file position is equal to %lld”, filp -> f_pos. This was the initial value of the current file position.
After that, let’s print one more statement here. new value of the filp-> f_pos.
Let me write as current value of the file position. Let me save and exit.
And make host. Let’s go back to our code, and let’s check some other methods. And in the open method, we are not doing anything. Because if you think you can do some initialization of the device, you can do here, but our device is a pseudo device, no IOs are involved with this device. So, it’s just a memory array. I don’t think we need to do any initialization or open kind of thing for this device.
That’s why what we can do is we can just return open was successful. The return 0 indicates open was successful. And for the release also, I don’t want to write any code here, we just return release was successful. We completed implementing all our methods and in the next article, let’s test this. I will see you in the next article.
FastBit Embedded Brain Academy Courses
Click here: https://fastbitlab.com/course1